package com.zyh.scs.admin.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zyh.scs.admin.api.bo.NotifyBo;
import com.zyh.scs.admin.api.constant.UserStateEnum;
import com.zyh.scs.admin.api.constant.open.CodeSet;
import com.zyh.scs.admin.api.constant.open.OrderStatus;
import com.zyh.scs.admin.api.dto.open.TransactionDetailDTO;
import com.zyh.scs.admin.api.dto.open.*;
import com.zyh.scs.admin.api.entity.*;
import com.zyh.scs.admin.api.utils.UserTypeToNameUtil;
import com.zyh.scs.admin.api.vo.UserCompanyVO;
import com.zyh.scs.admin.api.vo.open.*;
import com.zyh.scs.admin.base.open.*;
import com.zyh.scs.admin.mapper.*;
import com.zyh.scs.admin.service.SysUserService;
import com.zyh.scs.admin.service.UserAccountOpenService;
import com.zyh.scs.admin.utils.HeaderInfo;
import com.zyh.scs.admin.utils.HeaderUtil;
import com.zyh.scs.admin.utils.OtherThingHelper;
import com.zyh.scs.admin.utils.UUID;
import com.zyh.scs.common.core.exception.OpenException;
import com.zyh.scs.common.core.exception.OpenResponseCode;
import com.zyh.scs.common.core.util.MinioUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author hwh
 * @ClassName: 账户中心开发open接口实现$
 * @Description: $
 * @Date $
 * @Version 1.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserAccountOpenServiceImpl implements UserAccountOpenService {

    private final SysUserMapper sysUserMapper;

    private final SysUserService sysUserService;

    private final UserTransactionMapper userTransactionMapper;

    private final UserPaymentMapper userPaymentMapper;

    private final UserRechargeRecordMapper userRechargeRecordMapper;

    private final UserDepartmentInfoMapper userDepartmentInfoMapper;

    private final UserOrderInfoMapper userOrderInfoMapper;

    private final UserDeductionMapper userDeductionMapper;

    private final UserCationMapper userCationMapper;

    private final MinioUtil minioUtil;

    private final OtherThingHelper callbackHelper;

    private final String XLSX = ".xlsx";

    private final RedissonClient redissonClient;

    private static final String USER_CATION_KEY = "USER_CATION_KEY";

    /**
     * 个人用户id
     */
    private static final String OPEN_USERID_TOKEN = "OPEN_USERID_TOKEN";

    /**
     * 个人串码
     */
    private static final String OPEN_USERID_CODE = "OPEN_USERID_CODE";

    private final HeaderUtil headerUtil;


    @Override
    public LaoSheCheckResponse<UserAccountVO> checkUserAccount(UserAccountDto userAccountDto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheCheckResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        if (userAccountDto.getSerialType().equals("1")) {
            //手机号
            queryWrapper.eq(SysUser::getPhone, userAccountDto.getSerialValue());
        }
        if (userAccountDto.getSerialType().equals("2")) {
            //工号
            queryWrapper.eq(SysUser::getUserJobNumber, userAccountDto.getSerialValue());
        }
        if (userAccountDto.getSerialType().equals("3")) {
            //guid
            queryWrapper.eq(SysUser::getGuid, userAccountDto.getSerialValue());
        }
        if (userAccountDto.getSerialType().equals("4")) {
            //餐食卡号
            queryWrapper.eq(SysUser::getUserMealsNumber, userAccountDto.getSerialValue());
        }
        if (userAccountDto.getSerialType().equals("5")) {
            //企微用户id 暂时还没有
            queryWrapper.eq(SysUser::getQqOpenid, userAccountDto.getSerialValue());
        }
        queryWrapper.orderByDesc(SysUser::getCreateTime).last(" limit 1");
        SysUser sysUser = sysUserMapper.selectOne(queryWrapper);
        if (sysUser == null) {
            //用户不存在
            return LaoSheCheckResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
        }
        if (StrUtil.isBlank(sysUser.getUserJobNumber())) {
            //用户不存在
            return LaoSheCheckResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
        }
        UserAccountVO userAccountVO = getUserAccountVO(sysUser);
        if (sysUser.getCardState().equals("2")) {
            userAccountVO.setBalance(BigDecimal.ZERO);
        }
        if (sysUser.getCashState().equals("2")) {
            userAccountVO.setCashBalance(BigDecimal.ZERO);
        }
        log.info("验证账户有效性及查询余额接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(userAccountVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheCheckResponse.successCheck(userAccountVO, headerInfo.getTraceId());
    }

    private @NotNull UserAccountVO getUserAccountVO(SysUser sysUser) {
        UserAccountVO userAccountVO = new UserAccountVO();
        userAccountVO.setUserJobNum(sysUser.getUserJobNumber());
        userAccountVO.setUserType(sysUser.getUserType());
        userAccountVO.setStatus(sysUser.getLockFlag().equals(UserStateEnum.NORMAL.getCode()) ? "1" : "2");
        userAccountVO.setUserId(sysUser.getUserId());
        userAccountVO.setGuid(sysUser.getGuid());
        userAccountVO.setName(sysUser.getUsername());
        userAccountVO.setMobile(sysUser.getPhone());
        userAccountVO.setBindCardStatus(sysUser.getIsTheCard().toString());
        userAccountVO.setBalance(sysUser.getCardAccount());
        userAccountVO.setCardId(sysUser.getUserMealsNumber());
        userAccountVO.setCashBalance(sysUser.getCashAccount());
        if (sysUser.getThirdDeptId() != null) {
            userAccountVO.setDeptId(sysUser.getThirdDeptId());
            UserDepartmentInfo userDepartmentInfo = userDepartmentInfoMapper.selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery().eq(UserDepartmentInfo::getDeptId, sysUser.getThirdDeptId()));
            if (userDepartmentInfo != null && StrUtil.isNotBlank(userDepartmentInfo.getOrgShortName())) {
                userAccountVO.setDeptName(userDepartmentInfo.getOrgShortName());
            }
        }
        return userAccountVO;
    }

    @Override
    public LaoSheResponse<String> getUserCode(UserPhoneDTO userPhoneDTO, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        //根据手机号查询用户
        SysUser sysUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getPhone, userPhoneDTO.getUserPhone()).eq(SysUser::getDelFlag, "0").orderByDesc(SysUser::getCreateTime).last(" limit 1"));
        if (sysUser == null) {
            return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
        }

        if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
            return LaoSheResponse.error(CodeSet.USER_STATUS_EXCEPTION.getCode(), "用户账户已禁用", headerInfo.getTraceId());
        }

        //生成token
        String token = UUID.userToken();
        //存入redis中 过期时间一分钟
        RBucket<String> tokenRedis = redissonClient.getBucket(OPEN_USERID_CODE + token);
        tokenRedis.set(sysUser.getGuid(), Duration.ofSeconds(70L));
        log.info("个人串码 返回值: token: {}, traceId: {}, 接口响应时间: {}（毫秒）", token, headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(token, headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<UserAccountVO> getCodeToInfo(UserCodeDTO userCodeDTO, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        if (userCodeDTO.getOperQrCode().contains("#GDSH#")) {
            final String[] split = userCodeDTO.getOperQrCode().split("#GDSH#");
            final String split1 = split[0];
            if (!split1.isEmpty()) {
                userCodeDTO.setOperQrCode(split1);
            }
        }
        RBucket<String> bucket = redissonClient.getBucket(OPEN_USERID_CODE + userCodeDTO.getOperQrCode());
        String guid = bucket.get();
        if (StrUtil.isBlank(guid)) {
            return LaoSheResponse.error(CodeSet.OPER_QR_CODE_EXPIRED, headerInfo.getTraceId());
        }

        SysUser sysUser = sysUserMapper.selectByGuid(guid);
        if (sysUser == null) {
            //用户不存在
            return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
        }
        if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
            //该用户已禁用
            return LaoSheResponse.error(CodeSet.USER_STATUS_EXCEPTION.getCode(), "用户账户已禁用", headerInfo.getTraceId());
        }
        if (StrUtil.isBlank(sysUser.getUserJobNumber())) {
            //用户不存在
            return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
        }
        UserAccountVO userAccountVO = getUserAccountVO(sysUser);
        //删除缓存
        //TODO 暂时不需要
//        RedisUtil.remove(OPEN_USERID_CODE + userCodeDTO.getOperQrCode());
        log.info("个人码查询用户信息接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(userAccountVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(userAccountVO, headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<String> sendToken(String userPhone, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        SysUser sysUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getPhone, userPhone).eq(SysUser::getDelFlag, "0").orderByDesc(SysUser::getCreateTime).last(" limit 1"));
        if (sysUser == null) {
            return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
        }

        if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
            return LaoSheResponse.error(CodeSet.USER_STATUS_EXCEPTION.getCode(), "用户账户已禁用", headerInfo.getTraceId());
        }

        //生成token
        String token = UUID.userToken();
        //存入redis中 过期时间一分钟
        RBucket<String> tokenRedis = redissonClient.getBucket(OPEN_USERID_TOKEN + token);
        tokenRedis.set(sysUser.getUserId().toString(), Duration.ofSeconds(300L));
        //记录新的token信息
        log.info("获取token 返回值 当前用户信息为：{}，token为：{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(sysUser), token, headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(token, headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<UserAccountVO> queryAccountByToken(String token, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        RBucket<String> bucket = redissonClient.getBucket(OPEN_USERID_TOKEN + token);
        String value = bucket.get();
        if (StrUtil.isBlank(value)) {
            return LaoSheResponse.error(CodeSet.OPER_QR_TOKEN_EXPIRED, headerInfo.getTraceId());
        }
        Long userId = null;
        if (StrUtil.isNotBlank(value)) {
            if (!UserTypeToNameUtil.canConvertToLong(value)) {
                return LaoSheResponse.error(CodeSet.OPER_QR_TOKEN_EXPIRED, headerInfo.getTraceId());
            } else {
                userId = Long.valueOf(value);
            }
        }
        SysUser sysUser = sysUserMapper.selectById(userId);
        if (sysUser == null) {
            //用户不存在
            return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
        }
        if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
            //该用户已禁用
            return LaoSheResponse.error(CodeSet.USER_STATUS_EXCEPTION.getCode(), "用户账户已禁用", headerInfo.getTraceId());
        }
        if (StrUtil.isBlank(sysUser.getUserJobNumber())) {
            //用户不存在
            return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
        }
        UserAccountVO userAccountVO = getUserAccountVO(sysUser);
        // TODO 暂时不需要
        //删除缓存
//        RedisUtil.remove(OPEN_USERID_TOKEN + token);
        log.info("通过token获取用户信息 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(userAccountVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(userAccountVO, headerInfo.getTraceId());
    }

    @Override
    public LaoSheAccountTotalResponse<List<UserAccountVO>> userAccountPageList(UserAccountPageDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheAccountTotalResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        // 根据 商户ID/开始结束时间/分页参数 获取对账数据
        int pageNum = Integer.parseInt(dto.getPageNum());
        int pageSize = Integer.parseInt(dto.getPageSize());
        if (100 < pageSize) {
            pageSize = 100;
        }
        IPage<SysUser> page = new Page<>(pageNum, pageSize);
        IPage<SysUser> sysUserIPage = sysUserMapper.selectPage(page, Wrappers.<SysUser>lambdaQuery().eq(StrUtil.isNotBlank(dto.getUserPhone()), SysUser::getPhone, dto.getUserPhone()).eq(StrUtil.isNotBlank(dto.getCardId()), SysUser::getUserMealsNumber, dto.getCardId()).eq(StrUtil.isNotBlank(dto.getUserName()), SysUser::getUsername, dto.getUserName()).eq(StrUtil.isNotBlank(dto.getUserJobNum()), SysUser::getUserJobNumber, dto.getUserJobNum()).eq(SysUser::getIsAdmin, 1));
        List<UserAccountVO> userVoList = new ArrayList<>();
        List<SysUser> userInfoList = sysUserIPage.getRecords();

        BigDecimal userBalance = BigDecimal.ZERO;
        for (SysUser sysUser : userInfoList) {
            if (sysUser == null) {
                continue;
            }
            UserAccountVO userAccountVO = getUserAccountVO(sysUser);
            userBalance = userBalance.add(sysUser.getCardAccount());
            userVoList.add(userAccountVO);
        }
        log.info("查询用户分页列表接口 返回值:{}, 获取的总条数： {}, 餐卡余额总金额： {}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(userVoList), sysUserIPage.getTotal(), userBalance, headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheAccountTotalResponse.successData(userVoList, headerInfo.getTraceId(), sysUserIPage.getTotal(), userBalance);
    }

    @Override
    public LaoSheResponse<String> userAccountSync(UserSyncDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        if (StrUtil.isBlank(dto.getMobile()) && StrUtil.isBlank(dto.getUserJobNum())) {
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "手机号和工号必填一个", headerInfo.getTraceId());
        }
        if (dto.getUpdateType() != 1) {
            if (StrUtil.isBlank(dto.getGuid())) {
                return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "修改和删除时用戶guid不能为空", headerInfo.getTraceId());
            }
        }
        //添加
        if (dto.getUpdateType() == 1) {
            //添加
            SysUser userUpdateDto = getUserUpdateDto(dto);
            sysUserService.save(userUpdateDto);
        }
        if (dto.getUpdateType() == 2) {
            //更新
            if (!UserTypeToNameUtil.canConvertToLong(dto.getGuid()) || sysUserMapper.selectById(dto.getGuid()) == null) {
                return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
            }
            SysUser userUpdateDto = getUserUpdateDto(dto);
            sysUserService.updateByGuid(userUpdateDto);
        }
        if (dto.getUpdateType() == 3) {
            //删除
            if (!UserTypeToNameUtil.canConvertToLong(dto.getGuid()) || sysUserMapper.selectById(dto.getGuid()) == null) {
                return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
            }
            SysUser sysUser = new SysUser();
            sysUser.setDelFlag("1");
            sysUser.setGuid(dto.getGuid());
            sysUser.setPullStatus(1);
            sysUserService.updateByGuid(sysUser);
        }
        return LaoSheResponse.successData("成功", headerInfo.getTraceId());
    }

    private static @NotNull SysUser getUserUpdateDto(UserSyncDTO dto) {
        SysUser userUpdateDto = new SysUser();
        userUpdateDto.setPhone(dto.getMobile());
        userUpdateDto.setUserJobNumber(dto.getUserJobNum());
        userUpdateDto.setUsername(dto.getName());
        userUpdateDto.setUserMealsNumber(dto.getCardId());
//        userUpdateDto.setDeptId(Long.valueOf(dto.getDeptId()));
        userUpdateDto.setThirdDeptId(dto.getDeptId());
        userUpdateDto.setDeptName(dto.getDeptName());
        userUpdateDto.setLockFlag(dto.getStatus().equals("1") ? UserStateEnum.NORMAL.getCode() : UserStateEnum.LOCK.getCode());
        userUpdateDto.setGuid(dto.getGuid());
        return userUpdateDto;
    }

    @Override
    public LaoSheResponse<String> userDeptSync(DeptSyncDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        if (dto.getUpdateType() == 1) {
            //添加
            UserDepartmentInfo departmentInfo = new UserDepartmentInfo();
            departmentInfo.setDeptId(dto.getDeptId());
            departmentInfo.setOrgShortName(dto.getDeptName());
            departmentInfo.setParentId(dto.getParentId());
            departmentInfo.setApplyEvent("2");
            departmentInfo.setOrgStatus("1");
            userDepartmentInfoMapper.insert(departmentInfo);
        }
        if (dto.getUpdateType() == 2) {
            UserDepartmentInfo userDepartmentInfo = userDepartmentInfoMapper.selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery().eq(UserDepartmentInfo::getDeptId, dto.getDeptId()).eq(UserDepartmentInfo::getApplyEvent, "2").eq(UserDepartmentInfo::getOrgStatus, "1").last(" limit 1"));
            //更新
            if (userDepartmentInfo == null) {
                throw new OpenException(OpenResponseCode.DEPT_IS_NOT);
            }
            userDepartmentInfo.setDeptId(dto.getDeptId());
            userDepartmentInfo.setParentId(dto.getParentId());
            userDepartmentInfo.setOrgShortName(dto.getDeptName());
            userDepartmentInfoMapper.updateById(userDepartmentInfo);
        }
        return LaoSheResponse.successData("成功", headerInfo.getTraceId());
    }


    @Override
    public LaoSheResponse<UserDeductionVO> deduction(UserDeductionDTO dto, HttpServletRequest request) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("订单扣减-header耗时处理");
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

//        guid、物理卡号、手机号必传其一，优先校验guid，其次是物理卡号，最后是用户手机号

        if (StrUtil.isBlank(dto.getGuid()) && StrUtil.isBlank(dto.getCardId()) && StrUtil.isBlank(dto.getUserPhone())) {
            return LaoSheResponse.error(CodeSet.SERIAL_EXIST.getCode(), "guid、物理卡号、手机号 必传其一", headerInfo.getTraceId());
        }

        SysUser sysUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
                .eq(StrUtil.isNotBlank(dto.getGuid()), SysUser::getGuid, dto.getGuid())
                .eq(StrUtil.isNotBlank(dto.getCardId()), SysUser::getUserMealsNumber, dto.getCardId())
                .eq(StrUtil.isNotBlank(dto.getUserPhone()), SysUser::getPhone, dto.getUserPhone())
                .orderByDesc(SysUser::getCreateTime)
                .last(" limit 1"));

        if (sysUser == null) {
            return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
        }

        if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
            return LaoSheResponse.error(CodeSet.USER_STATUS_EXCEPTION, headerInfo.getTraceId());
        }

        stopWatch.stop();
        UserDeductionVO userDeductionVO = new UserDeductionVO();

        RLock lock = redissonClient.getLock("getAccountLock" + sysUser.getGuid());

        try {

            lock.lock(10, TimeUnit.SECONDS);

            UserTransaction userTransactionIsNot = userTransactionMapper.selectOne(Wrappers.<UserTransaction>lambdaQuery()
                    .eq(StrUtil.isNotBlank(dto.getTransactionSerial()), UserTransaction::getThirdRechargeStream, dto.getTransactionSerial())
                    .last(" limit 1"));

            if (userTransactionIsNot != null) {
                return LaoSheResponse.error(CodeSet.SERIAL_EXIST, headerInfo.getTraceId());
            }

            stopWatch.start("cation查询处理");
            // 直接获取锁，阻塞式
            // 执行业务逻辑
            UserCation userCation = callbackHelper.getRedisCation(headerInfo.getMerchantId());

            String note = null;
            if (userCation.getChannelType() == 1) {
                if (StrUtil.isNotBlank(dto.getOperQrCode())) {
                    note = StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() + ",满客宝二维码扣费" : "满客宝二维码扣费";
                } else {
                    note = StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() + ",满客宝订单扣费" : "满客宝订单扣费";
                }
            } else if (userCation.getChannelType() == 2) {
                if (StrUtil.isNotBlank(dto.getOperQrCode())) {
                    note = StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() + ",京东二维码扣费" : "京东二维码扣费";
                } else {
                    note = StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() + ",京东订单扣费" : "京东订单扣费";
                }
            } else if (userCation.getChannelType() == 3) {
                if (StrUtil.isNotBlank(dto.getOperQrCode())) {
                    note = StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() + ",好店二维码扣费" : "好店二维码扣费";
                } else {
                    note = StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() + ",好店订单扣费" : "好店订单扣费";
                }
            }
            stopWatch.stop();

            if (StrUtil.isBlank(dto.getGuid()) && StrUtil.isBlank(dto.getCardId()) && StrUtil.isBlank(dto.getUserPhone())) {
                return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "guid和手机号和物理卡号必填一个", headerInfo.getTraceId());
            }
            stopWatch.start("订单幂等校验");
            if (userOrderInfoMapper.selectOne(Wrappers.<UserOrderInfo>lambdaQuery()
                    .eq(UserOrderInfo::getOutOrderNo, dto.getOutTradeNo()).last(" limit 1")) != null) {
                return LaoSheResponse.error(CodeSet.ORDER_EXIST_DEBIT_SUCCESS, headerInfo.getTraceId());
            }
            stopWatch.stop();

            if (userTransactionMapper.selectOne(Wrappers.<UserTransaction>lambdaQuery()
                    .eq(UserTransaction::getThirdRechargeStream, dto.getTransactionSerial())
                    .orderByDesc(UserTransaction::getCreateTime).last(" limit 1")) != null) {
                return LaoSheResponse.error(CodeSet.SERIAL_EXIST, headerInfo.getTraceId());
            }

            UserOrderInfo userOrderInfo = new UserOrderInfo();
            BeanUtil.copyProperties(dto, userOrderInfo);
            userOrderInfo.setOrderId(UserTypeToNameUtil.setRechargeStream());
            final LocalDateTime now = LocalDateTime.now();
            userOrderInfo.setOutOrderTime(now);
            userOrderInfo.setOrderStatus(8);
            userOrderInfo.setTransactionSerial(dto.getTransactionSerial());
            userOrderInfo.setOutOrderNo(dto.getOutTradeNo());
            userOrderInfo.setStoreId(StrUtil.isNotBlank(dto.getStoreId()) ? dto.getStoreId() : null);
            userOrderInfo.setStoreName(StrUtil.isNotBlank(dto.getStoreName()) ? dto.getStoreName() : null);
            userOrderInfo.setShopName(StrUtil.isNotBlank(dto.getShopName()) ? dto.getShopName() : null);
            userOrderInfo.setMerchantId(StrUtil.isNotBlank(headerInfo.getMerchantId()) ? headerInfo.getMerchantId() : null);

            stopWatch.start("用户校验");
            SysUser user = sysUserMapper.selectByGuid(sysUser.getGuid());
            if (user == null) {
                return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
            }

            if (user.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
                return LaoSheResponse.error(CodeSet.USER_STATUS_EXCEPTION, headerInfo.getTraceId());
            }

            if (dto.getBalance() != null && dto.getBalance().compareTo(BigDecimal.ZERO) > 0) {
                if (user.getCardState().equals("2")) {
                    return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "账户餐卡账户冻结,无法扣费", headerInfo.getTraceId());
                }
            }
            if (dto.getCashBalance() != null && dto.getCashBalance().compareTo(BigDecimal.ZERO) > 0) {
                if (user.getCashState().equals("2")) {
                    return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "账户现金账户冻结,无法扣费", headerInfo.getTraceId());
                }
            }
            if (dto.getBalance() == null && dto.getCashBalance() == null) {
                return LaoSheResponse.error(CodeSet.NOT_ALL_NULL, headerInfo.getTraceId());
            }

            if (dto.getBalance() != null && dto.getBalance().compareTo(user.getCardAccount()) > 0) {
                return LaoSheResponse.error(CodeSet.INSUFFICIENT_BALANCE, headerInfo.getTraceId());
            }

            if (dto.getCashBalance() != null && dto.getCashBalance().compareTo(user.getCashAccount()) > 0) {
                return LaoSheResponse.error(CodeSet.USER_CASH_ACCOUNT_INSUFFICIENT, headerInfo.getTraceId());
            }
            stopWatch.stop();

            userOrderInfo.setGuid(user.getGuid());
            userOrderInfo.setUserId(user.getUserId());

            String rechargeStreamCard = UserTypeToNameUtil.setRechargeStream();
            stopWatch.start("扣减流水&交易流水&动账");
            insertPay(rechargeStreamCard, userOrderInfo.getOrderId(), userOrderInfo.getOutOrderNo(), note, headerInfo.getMerchantId(), dto.getBalance(), dto.getCashBalance(), user, dto.getTransactionSerial());
            stopWatch.stop();
            stopWatch.start("订单入库");
            userOrderInfo.setRefundTime(now);
            userOrderInfo.setUserMealsNumber(StrUtil.isNotBlank(user.getUserMealsNumber()) ? user.getUserMealsNumber() : "");
            userOrderInfo.setUsername(StrUtil.isNotBlank(user.getUsername()) ? user.getUsername() : "");
            userOrderInfo.setPhone(StrUtil.isNotBlank(user.getPhone()) ? user.getPhone() : "");
            userOrderInfo.setUserJobNumber(StrUtil.isNotBlank(user.getUserJobNumber()) ? user.getUserJobNumber() : "");
            userOrderInfo.setNotes(StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() : note);
            userOrderInfo.setWhetSync("1");
            userOrderInfo.setUserBalance(dto.getBalance() != null ? dto.getBalance() : BigDecimal.ZERO);
            userOrderInfo.setCashBalance(dto.getCashBalance() != null ? dto.getCashBalance() : BigDecimal.ZERO);
            userOrderInfo.setAmount(userOrderInfo.getUserBalance().add(userOrderInfo.getCashBalance()));
            userOrderInfo.setUserType(user.getUserType());
            //福利卡账户退款金额
            final BigDecimal cardTo = Optional.ofNullable(dto.getBalance()).orElse(BigDecimal.ZERO);
            //现金账户退款金额
            final BigDecimal cashTo = Optional.ofNullable(dto.getCashBalance()).orElse(BigDecimal.ZERO);
            userOrderInfo.setAmount(cardTo.add(cashTo));
            userOrderInfoMapper.insert(userOrderInfo);
            stopWatch.stop();
            //异步通知mkb
            callbackHelper.callback(CallbackDTO.builder().orderCode(userOrderInfo.getOrderId()).oderMsg(OrderStatus.REFUND_SUCCESS.getDesc()).outTradeNo(dto.getOutTradeNo()).transactionSerial(dto.getTransactionSerial()).tradeSerial(userOrderInfo.getOrderId()).centerTime(now).tradeType("2").build(), headerInfo.getMerchantId());
            userDeductionVO = getUserDeductionVO(userOrderInfo.getOrderId(), user, dto.getBalance(), dto.getCashBalance(), dto.getOutTradeNo(), dto.getTransactionSerial());
            //异步通知好店
            final NotifyBo notifyBo = new NotifyBo();
            notifyBo.setGuid(dto.getGuid());
            notifyBo.setAmount(dto.getAmount());
            notifyBo.setUseTime(now);
            notifyBo.setRemark(dto.getNote());
            notifyBo.setOrderCode(dto.getOutTradeNo());
            notifyBo.setOperQrCode(dto.getOperQrCode());
            callbackHelper.notifyGoodShop(notifyBo);
        } catch (Exception e) {
            log.error("订单扣减失败：", e);
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "订单扣减失败", headerInfo.getTraceId());
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
            if (stopWatch.isRunning()) {
                stopWatch.stop();
            }
            log.info("订单扣费个步骤明细：{}", stopWatch.prettyPrint());
        }
        log.info("订单扣费接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(userDeductionVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(userDeductionVO, headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<TransactionDetailVO> transactionDetail(TransactionDetailDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        UserTransaction userTransaction = userTransactionMapper.selectOne(Wrappers.<UserTransaction>lambdaQuery().eq(UserTransaction::getThirdRechargeStream, dto.getTransactionSerial()).orderByDesc(UserTransaction::getCreateTime).last(" limit 1"));
        if (userTransaction == null) {
            return LaoSheResponse.error(CodeSet.TRANSACTION_FLOW_NOT_EXIST, headerInfo.getTraceId());
        }
        UserOrderInfo userOrderInfo = userOrderInfoMapper.selectOne(Wrappers.<UserOrderInfo>lambdaQuery().eq(UserOrderInfo::getTransactionSerial, dto.getTransactionSerial()).last(" limit 1"));
        if (userOrderInfo == null) {
            return LaoSheResponse.error(CodeSet.ORDER_NOT_EXIST, headerInfo.getTraceId());
        }
        TransactionDetailVO transactionDetailVO = new TransactionDetailVO();
        transactionDetailVO.setTradeNo(userTransaction.getOrderId());
        transactionDetailVO.setOutTradeNo(userTransaction.getOutOrderNo());
        transactionDetailVO.setTransactionSerial(dto.getTransactionSerial());
        transactionDetailVO.setGuid(userTransaction.getGuid());
        transactionDetailVO.setAmount(userTransaction.getTransactionNumber());
        transactionDetailVO.setTimestamp(UserTypeToNameUtil.getEpochSecond(userTransaction.getTransactionTime()));
        transactionDetailVO.setType(userTransaction.getTransactionType());
        transactionDetailVO.setTradeStatus(userTransaction.getAccountType());
        transactionDetailVO.setNote(userTransaction.getNotes());
        transactionDetailVO.setTradeSerial(userTransaction.getRechargeStream());
        log.info("交易流水查询接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(transactionDetailVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(transactionDetailVO, headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<TransactionDetailVO> payDetail(TransactionDetailDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        UserRechargeRecord userRechargeRecord = userRechargeRecordMapper
                .selectOne(Wrappers.<UserRechargeRecord>lambdaQuery()
                        .eq(UserRechargeRecord::getThirdRechargeStream, dto.getTransactionSerial())
                        .orderByDesc(UserRechargeRecord::getCreateTime).last(" limit 1"));
        if (userRechargeRecord == null) {
            return LaoSheResponse.error(CodeSet.TRANSACTION_FLOW_NOT_EXIST, headerInfo.getTraceId());
        }
        TransactionDetailVO transactionDetailVO = new TransactionDetailVO();
        transactionDetailVO.setTradeNo(userRechargeRecord.getRechargeStream());
        transactionDetailVO.setGuid(userRechargeRecord.getGuid());
        transactionDetailVO.setAmount(userRechargeRecord.getRechargeNumber());
        transactionDetailVO.setOutTradeNo(userRechargeRecord.getThirdRechargeStream());
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        transactionDetailVO.setTimestamp(UserTypeToNameUtil.getEpochSecond(userRechargeRecord.getCreateTime()));
        transactionDetailVO.setTradeTime(format.format(userRechargeRecord.getCreateTime()));
        transactionDetailVO.setNote(userRechargeRecord.getNotes());
        transactionDetailVO.setTradeStatus(userRechargeRecord.getRechargeType());
        transactionDetailVO.setTradeSerial(userRechargeRecord.getRechargeStream());
        log.info("充值流水查询接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(transactionDetailVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(transactionDetailVO, headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<OrderInfoExDto> orderRefund(OrderRefundDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        OrderInfoExDto orderInfoExDto = new OrderInfoExDto();

        //根据商户订单号查找
        UserOrderInfo userOrderInfo = userOrderInfoMapper
                .selectOne(Wrappers.<UserOrderInfo>lambdaQuery()
                        .eq(UserOrderInfo::getOutOrderNo, dto.getOutTradeNo())
                        .eq(UserOrderInfo::getMerchantId, headerInfo.getMerchantId())
                        .last("limit 1"));
        if (userOrderInfo == null) {
            return LaoSheResponse.error(CodeSet.ORDER_NOT_EXIST, headerInfo.getTraceId());
        }

        if (StrUtil.isBlank(userOrderInfo.getGuid())) {
            return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
        }

        RLock lock = redissonClient.getLock("getAccountLock" + userOrderInfo.getGuid());

        try {
            // 直接获取锁，阻塞式
            lock.lock(10, TimeUnit.SECONDS);
            userOrderInfo = userOrderInfoMapper
                    .selectOne(Wrappers.<UserOrderInfo>lambdaQuery()
                            .eq(UserOrderInfo::getOutOrderNo, dto.getOutTradeNo())
                            .eq(UserOrderInfo::getMerchantId, headerInfo.getMerchantId())
                            .last("limit 1"));
            if (userOrderInfo == null) {
                return LaoSheResponse.error(CodeSet.ORDER_NOT_EXIST, headerInfo.getTraceId());
            }

            if (userOrderInfo.getOrderStatus() == 10) {
                return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "订单已退款,无需重复退款", headerInfo.getTraceId());
            }

            UserTransaction userTransactionIsNot = userTransactionMapper.selectOne(Wrappers.<UserTransaction>lambdaQuery().eq(StrUtil.isNotBlank(dto.getTransactionSerial()), UserTransaction::getThirdRechargeStream, dto.getTransactionSerial())
                    .last(" limit 1"));

            if (userTransactionIsNot != null) {
                return LaoSheResponse.error(CodeSet.SERIAL_EXIST, headerInfo.getTraceId());
            }

            SysUser sysUser = sysUserMapper.selectByGuid(userOrderInfo.getGuid());

            if (sysUser == null) {
                return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
            }
            //福利卡账户退款金额
            final BigDecimal refundAmount = Optional.ofNullable(dto.getRefundAmount()).orElse(BigDecimal.ZERO);
            //现金账户退款金额
            final BigDecimal cashRefundAmount = Optional.ofNullable(dto.getCashRefundAmount()).orElse(BigDecimal.ZERO);

            if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
                return LaoSheResponse.error(CodeSet.USER_STATUS_EXCEPTION.getCode(), "用户账户已禁用", headerInfo.getTraceId());
            }

            if (refundAmount.compareTo(BigDecimal.ZERO) > 0) {
                if (sysUser.getCardState().equals("2")) {
                    return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "账户餐卡账户冻结,无法扣费", headerInfo.getTraceId());
                }
            }
            if (cashRefundAmount.compareTo(BigDecimal.ZERO) > 0) {
                if (sysUser.getCashState().equals("2")) {
                    return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "账户现金账户冻结,无法扣费", headerInfo.getTraceId());
                }
            }
            //福利卡余额校验
            //福利卡退款金额不为空，说明已经发起过退货   订单本身消耗的福利卡金额-已退款金额要>=退款金额
            if (refundAmount.compareTo(userOrderInfo.getUserBalance().subtract(userOrderInfo.getRefundAmount())) > 0) {
                return LaoSheResponse.error(CodeSet.EXCEEDS_REFUNDABLE_AMOUNT, headerInfo.getTraceId());
            }

            //现金账户余额校验
            //TODO 现金账户退款金额不为空，说明已经发起过退货   订单本身消耗的现金账户金额-已退款金额要>=退款金额
            if (cashRefundAmount.compareTo(userOrderInfo.getCashBalance().subtract(userOrderInfo.getCashRefundAmount())) > 0) {
                return LaoSheResponse.error(CodeSet.EXCEEDS_REFUNDABLE_AMOUNT, headerInfo.getTraceId());
            }

            //退款
            //TODO 生成退款流水
            //餐补
            // TODO 加缓存 UserCation
            UserCation userCation = callbackHelper.getRedisCation(headerInfo.getMerchantId());
            String note = "";
            if (userCation.getChannelType() == 1) {
                note = StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() + ",满客宝订单退款" : "满客宝订单退款";
            } else if (userCation.getChannelType() == 2) {
                note = StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() + ",京东订单退款" : "京东订单退款";
            } else if (userCation.getChannelType() == 3) {
                note = StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() + ",好店订单退款" : "好店订单退款";
            }

            //生成退款流水
            String rechargeStreamCard = UserTypeToNameUtil.setRechargeStream();
            String rechargeStreamCash = UserTypeToNameUtil.setRechargeStream();
            //餐补退款
            if (refundAmount.compareTo(BigDecimal.ZERO) > 0) {
                sysUser.setCardAccount(sysUser.getCardAccount().add(refundAmount));
                UserDeduction userDeductionCard = new UserDeduction();
                UserTransaction userTransactionCard = new UserTransaction();
                BeanUtil.copyProperties(sysUser, userDeductionCard);
                userDeductionCard.setAccountType("1");
                if (userCation.getChannelType() == 1) {
                    userDeductionCard.setPaymentChannel("1");
                    userTransactionCard.setTransactionType("3");
                }
                if (userCation.getChannelType() == 2) {
                    userDeductionCard.setPaymentChannel("2");
                    userTransactionCard.setTransactionType("5");
                }
                if (userCation.getChannelType() == 3) {
                    userDeductionCard.setPaymentChannel("4");
                    userTransactionCard.setTransactionType("8");
                }
                userDeductionCard.setTransactionTime(LocalDateTime.now());
                userDeductionCard.setRechargeStream(rechargeStreamCard);
                userDeductionCard.setNotes(note);
                userDeductionCard.setDeductionNumber(refundAmount);
                userDeductionCard.setOrderId(userOrderInfo.getOrderId());
                userDeductionCard.setOutOrderNo(userOrderInfo.getOutOrderNo());
                userDeductionCard.setThirdRechargeStream(dto.getTransactionSerial());
                userDeductionMapper.insert(userDeductionCard);
                BeanUtil.copyProperties(userDeductionCard, userTransactionCard);
                userTransactionCard.setTransactionNumber(refundAmount);
                userTransactionCard.setMerchantNumber(headerInfo.getMerchantId());
                userTransactionCard.setTradeType(1);
                userDeductionCard.setUserMealsNumber(sysUser.getUserMealsNumber());
                userTransactionMapper.insert(userTransactionCard);
                //sysUserMapper.updateById(sysUser);
            }
            //现金退款
            if (cashRefundAmount.compareTo(BigDecimal.ZERO) > 0) {
                sysUser.setCashAccount(sysUser.getCashAccount().add(cashRefundAmount));
                UserDeduction userDeductionCash = new UserDeduction();
                UserTransaction userTransactionCash = new UserTransaction();
                BeanUtil.copyProperties(sysUser, userDeductionCash);
                userDeductionCash.setAccountType("2");
                if (userCation.getChannelType() == 1) {
                    userDeductionCash.setPaymentChannel("1");
                    userTransactionCash.setTransactionType("3");
                }
                if (userCation.getChannelType() == 2) {
                    userDeductionCash.setPaymentChannel("2");
                    userTransactionCash.setTransactionType("5");
                }
                if (userCation.getChannelType() == 3) {
                    userDeductionCash.setPaymentChannel("4");
                    userTransactionCash.setTransactionType("8");
                }
                userDeductionCash.setTransactionTime(LocalDateTime.now());
                userDeductionCash.setRechargeStream(rechargeStreamCash);
                userDeductionCash.setNotes(note);
                userDeductionCash.setDeductionNumber(cashRefundAmount);
                userDeductionCash.setOrderId(userOrderInfo.getOrderId());
                userDeductionCash.setOutOrderNo(userOrderInfo.getOutOrderNo());
                userDeductionCash.setThirdRechargeStream(dto.getTransactionSerial());
                userDeductionMapper.insert(userDeductionCash);

                BeanUtil.copyProperties(userDeductionCash, userTransactionCash);
                userTransactionCash.setTransactionNumber(cashRefundAmount);
                userTransactionCash.setMerchantNumber(headerInfo.getMerchantId());
                userTransactionCash.setTradeType(1);
                userTransactionCash.setUserMealsNumber(sysUser.getUserMealsNumber());
                userTransactionMapper.insert(userTransactionCash);
                //sysUserMapper.updateById(sysUser);
            }
            sysUserService.lambdaUpdate()
                    .eq(SysUser::getGuid, sysUser.getGuid())
                    .setIncrBy(refundAmount.compareTo(BigDecimal.ZERO) > 0
                            , SysUser::getCardAccount, refundAmount)
                    .setIncrBy(cashRefundAmount.compareTo(BigDecimal.ZERO) > 0
                            , SysUser::getCashAccount, cashRefundAmount)
                    .set(SysUser::getUpdateBy, sysUser.getGuid())
                    .set(SysUser::getUpdateTime, LocalDateTime.now())
                    .update();

            if (StrUtil.isNotBlank(userOrderInfo.getOrderId())) {
                orderInfoExDto.setTradeNo(userOrderInfo.getOrderId());
            }
            orderInfoExDto.setOutTradeNo(dto.getOutTradeNo());
            orderInfoExDto.setGuid(userOrderInfo.getGuid());
            orderInfoExDto.setAmount(userOrderInfo.getAmount());
            orderInfoExDto.setTimestamp(String.valueOf(System.currentTimeMillis()));
            if (StrUtil.isNotBlank(userOrderInfo.getStoreId())) {
                orderInfoExDto.setStoreId(userOrderInfo.getStoreId());
            }
            if (StrUtil.isNotBlank(userOrderInfo.getStoreName())) {
                orderInfoExDto.setStoreName(userOrderInfo.getStoreName());
            }
            if (StrUtil.isNotBlank(dto.getNote())) {
                orderInfoExDto.setNote(dto.getNote());
            }
            orderInfoExDto.setTradeSerial(userOrderInfo.getOrderId());
            orderInfoExDto.setTransactionSerial(dto.getTransactionSerial());
            userOrderInfo.setRefundAmount(userOrderInfo.getRefundAmount().add(dto.getRefundAmount()));
            userOrderInfo.setCashRefundAmount(userOrderInfo.getCashRefundAmount().add(dto.getCashRefundAmount()));
            if (userOrderInfo.getUserBalance().subtract(userOrderInfo.getRefundAmount()).compareTo(BigDecimal.ZERO) > 0 || userOrderInfo.getCashBalance().subtract(userOrderInfo.getCashRefundAmount()).compareTo(BigDecimal.ZERO) > 0) {
                userOrderInfo.setOrderStatus(12);
                orderInfoExDto.setStatus(2);
            } else {
                userOrderInfo.setOrderStatus(10);
                orderInfoExDto.setStatus(3);
            }
            orderInfoExDto.setRefundAmount(userOrderInfo.getRefundAmount());
            orderInfoExDto.setCashRefundAmount(userOrderInfo.getCashRefundAmount());
            userOrderInfo.setRefundTime(UserTypeToNameUtil.getStringToTime(dto.getTimestamp()));
            userOrderInfo.setAllRefundAmount(userOrderInfo.getAllRefundAmount().add(dto.getRefundAmount()).add(dto.getCashRefundAmount()));
            userOrderInfoMapper.updateById(userOrderInfo);
            try {
                Date now = new Date();
                callbackHelper.callback(CallbackDTO.builder().orderCode(userOrderInfo.getOrderId()).oderMsg(OrderStatus.REFUND_SUCCESS.getDesc()).outTradeNo(dto.getOutTradeNo()).transactionSerial(dto.getTransactionSerial()).tradeSerial(userOrderInfo.getOrderId()).centerTime(LocalDateTime.ofInstant(now.toInstant(), ZoneOffset.ofHours(8))).tradeType("4").build(), headerInfo.getMerchantId());
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        } catch (Exception e) {
            log.error("退款失败：", e);
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "退款失败", headerInfo.getTraceId());
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        log.info("订单退款接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(orderInfoExDto), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(orderInfoExDto, headerInfo.getTraceId());
    }

    /**
     * 生成退款流水和交易流水
     *
     * @param userTransaction
     * @param userDeduction
     * @param accountType
     * @param time
     * @param transactionSerial
     * @param note
     * @param refundAmount
     * @param sysUser
     * @param localDateTime
     * @return
     */
    private void getUserDeduction(String orderId, String outOrderNo, String merchantId, String rechargeStream, UserTransaction userTransaction, UserDeduction userDeduction, String accountType, String time, String transactionSerial, String note, BigDecimal refundAmount, SysUser sysUser, LocalDateTime localDateTime) {
        //生成退款
        //金额回滚
        sysUserMapper.updateById(sysUser);
        BeanUtil.copyProperties(sysUser, userDeduction);
        userDeduction.setAccountType(accountType);
        // TODO 加缓存 UserCation
        UserCation userCation = callbackHelper.getRedisCation(merchantId);
        if (userCation.getChannelType() == 1) {
            userDeduction.setPaymentChannel("1");
            userTransaction.setTransactionType("3");
        }
        if (userCation.getChannelType() == 2) {
            userDeduction.setPaymentChannel("2");
            userTransaction.setTransactionType("5");
        }
        if (userCation.getChannelType() == 3) {
            userDeduction.setPaymentChannel("4");
            userTransaction.setTransactionType("8");
        }

        if (StrUtil.isNotBlank(time)) {
            userDeduction.setTransactionTime(UserTypeToNameUtil.getStringToTime(time));
        } else {
            userDeduction.setTransactionTime(localDateTime);
        }
        userDeduction.setRechargeStream(rechargeStream);
        if (StrUtil.isNotBlank(transactionSerial)) {
            userDeduction.setThirdRechargeStream(transactionSerial);
        }
        if (StrUtil.isNotBlank(note)) {
            userDeduction.setNotes(note);
        }
        userDeduction.setDeductionNumber(refundAmount);
        userDeduction.setOrderId(orderId);
        userDeduction.setOutOrderNo(outOrderNo);
        userDeductionMapper.insert(userDeduction);
        //生成交易流水
        BeanUtil.copyProperties(sysUser, userTransaction);
        userTransaction.setMerchantNumber(merchantId);
        userTransaction.setRechargeStream(rechargeStream);
        if (StrUtil.isNotBlank(transactionSerial)) {
            userTransaction.setThirdRechargeStream(transactionSerial);
        }
        userTransaction.setTransactionNumber(refundAmount);
        userTransaction.setAccountType(accountType);
        if (StrUtil.isNotBlank(time)) {
            userTransaction.setTransactionTime(UserTypeToNameUtil.getStringToTime(time));
        } else {
            userTransaction.setTransactionTime(localDateTime);
        }
        if (StrUtil.isNotBlank(note)) {
            userTransaction.setNotes(note);
        }
        userTransaction.setOrderId(orderId);
        userTransaction.setOutOrderNo(outOrderNo);
        userTransaction.setTradeType(1);
        userTransactionMapper.insert(userTransaction);
    }

    @Override
    public LaoSheResponse<OrderInfoExDto> cancel(OrderCancelDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        OrderInfoExDto orderInfoExDto = new OrderInfoExDto();

        //根据商户订单号查找
        UserOrderInfo userOrderInfo = userOrderInfoMapper
                .selectOne(Wrappers.<UserOrderInfo>lambdaQuery()
                        .eq(UserOrderInfo::getMerchantId, headerInfo.getMerchantId())
                        .eq(UserOrderInfo::getOutOrderNo, dto.getOutTradeNo()).last("limit 1"));

        if (userOrderInfo == null) {
            return LaoSheResponse.error(CodeSet.ORDER_NOT_EXIST, headerInfo.getTraceId());
        }

        RLock lock = redissonClient.getLock("getAccountLock" + userOrderInfo.getGuid());
        try {
            // 直接获取锁，阻塞式
            lock.lock(10, TimeUnit.SECONDS);
            userOrderInfo = userOrderInfoMapper
                    .selectOne(Wrappers.<UserOrderInfo>lambdaQuery()
                            .eq(UserOrderInfo::getMerchantId, headerInfo.getMerchantId())
                            .eq(UserOrderInfo::getOutOrderNo, dto.getOutTradeNo()).last("limit 1"));

            if (userOrderInfo == null) {
                return LaoSheResponse.error(CodeSet.ORDER_NOT_EXIST, headerInfo.getTraceId());
            }

            //订单已关闭，不可撤销
            if (userOrderInfo.getOrderStatus() == 13) {
                return LaoSheResponse.error(CodeSet.ORDER_CANCELLED, headerInfo.getTraceId());
            }

            //订单已发起退款
            if (userOrderInfo.getOrderStatus() == 10 || userOrderInfo.getOrderStatus() == 9) {
                return LaoSheResponse.error(CodeSet.ORDER_IRREVOCABLE, headerInfo.getTraceId());
            }

            UserTransaction userTransactionIsNot = userTransactionMapper.selectOne(Wrappers.<UserTransaction>lambdaQuery().eq(StrUtil.isNotBlank(dto.getTransactionSerial()), UserTransaction::getThirdRechargeStream, dto.getTransactionSerial())
                    .last(" limit 1"));

            if (userTransactionIsNot != null) {
                return LaoSheResponse.error(CodeSet.SERIAL_EXIST, headerInfo.getTraceId());
            }

            SysUser sysUser = sysUserMapper.selectByGuid(userOrderInfo.getGuid());
            if (sysUser == null) {
                return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
            }

            if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
                return LaoSheResponse.error(CodeSet.USER_STATUS_EXCEPTION.getCode(), "用户账户已禁用", headerInfo.getTraceId());
            }
            // 直接获取锁，阻塞式
            orderInfoExDto.setTradeNo(userOrderInfo.getOrderId());
            orderInfoExDto.setOutTradeNo(dto.getOutTradeNo());
            orderInfoExDto.setGuid(userOrderInfo.getGuid());
            orderInfoExDto.setAmount(userOrderInfo.getAmount());
            orderInfoExDto.setTimestamp(UserTypeToNameUtil.getEpochSecond(userOrderInfo.getCreateTime()));
            if (StrUtil.isNotBlank(userOrderInfo.getStoreId())) {
                orderInfoExDto.setStoreId(userOrderInfo.getStoreId());
            }
            if (StrUtil.isNotBlank(userOrderInfo.getStoreName())) {
                orderInfoExDto.setStoreName(userOrderInfo.getStoreName());
            }
            if (StrUtil.isNotBlank(dto.getNote())) {
                orderInfoExDto.setNote(dto.getNote());
            }
            String rechargeStream = UserTypeToNameUtil.setRechargeStream();
            orderInfoExDto.setStatus(5);
            orderInfoExDto.setTradeSerial(userOrderInfo.getOrderId());
            orderInfoExDto.setTransactionSerial(StrUtil.isNotBlank(dto.getTransactionSerial()) ? dto.getTransactionSerial() : "");
            //回滚账户余额 跟改订单状态
            //生成退款流水

            UserCation userCation = callbackHelper.getRedisCation(headerInfo.getMerchantId());

            //餐补退款
            if (userOrderInfo.getUserBalance().compareTo(BigDecimal.ZERO) > 0) {
                sysUser.setCardAccount(sysUser.getCardAccount().add(userOrderInfo.getUserBalance()));
                UserDeduction userDeductionCard = new UserDeduction();
                UserTransaction userTransactionCard = new UserTransaction();
                BeanUtil.copyProperties(sysUser, userDeductionCard);
                userDeductionCard.setAccountType("1");
                if (userCation.getChannelType() == 1) {
                    userDeductionCard.setPaymentChannel("1");
                    userTransactionCard.setTransactionType("3");
                    if (StrUtil.isNotBlank(dto.getNote())) {
                        userDeductionCard.setNotes(dto.getNote() + ",满客宝撤销");
                    } else {
                        userDeductionCard.setNotes("满客宝撤销");
                    }

                }
                if (userCation.getChannelType() == 2) {
                    userDeductionCard.setPaymentChannel("2");
                    userTransactionCard.setTransactionType("5");
                    if (StrUtil.isNotBlank(dto.getNote())) {
                        userDeductionCard.setNotes(dto.getNote() + ",京东撤销");
                    } else {
                        userDeductionCard.setNotes("京东撤销");
                    }
                }
                if (userCation.getChannelType() == 3) {
                    userDeductionCard.setPaymentChannel("4");
                    userTransactionCard.setTransactionType("8");
                    if (StrUtil.isNotBlank(dto.getNote())) {
                        userDeductionCard.setNotes(dto.getNote() + ",好店撤销");
                    } else {
                        userDeductionCard.setNotes("好店撤销");
                    }
                }

                userDeductionCard.setTransactionTime(LocalDateTime.now());
                userDeductionCard.setRechargeStream(UserTypeToNameUtil.setRechargeStream());
                userDeductionCard.setThirdRechargeStream(StrUtil.isNotBlank(dto.getTransactionSerial()) ? dto.getTransactionSerial() : "");
                userDeductionCard.setDeductionNumber(userOrderInfo.getUserBalance());
                userDeductionCard.setOrderId(userOrderInfo.getOrderId());
                userDeductionCard.setOutOrderNo(userOrderInfo.getOutOrderNo());
                userDeductionMapper.insert(userDeductionCard);

                BeanUtil.copyProperties(userDeductionCard, userTransactionCard);
                userTransactionCard.setTransactionNumber(userOrderInfo.getUserBalance());
                userTransactionCard.setMerchantNumber(headerInfo.getMerchantId());
                userTransactionCard.setOrderId(userOrderInfo.getOrderId());
                userTransactionCard.setOutOrderNo(userOrderInfo.getOutOrderNo());
                userTransactionCard.setThirdRechargeStream(StrUtil.isNotBlank(dto.getTransactionSerial()) ? dto.getTransactionSerial() : "");
                userTransactionCard.setTradeType(1);
                userTransactionCard.setUserMealsNumber(sysUser.getUserMealsNumber());
                userTransactionMapper.insert(userTransactionCard);
            }
            //现金退款
            if (userOrderInfo.getCashBalance().compareTo(BigDecimal.ZERO) > 0) {
                sysUser.setCashAccount(sysUser.getCashAccount().add(userOrderInfo.getCashBalance()));
                UserDeduction userDeductionCash = new UserDeduction();
                UserTransaction userTransactionCash = new UserTransaction();
                BeanUtil.copyProperties(sysUser, userDeductionCash);
                userDeductionCash.setAccountType("2");
                if (userCation.getChannelType() == 1) {
                    userDeductionCash.setPaymentChannel("1");
                    userTransactionCash.setTransactionType("3");
                    if (StrUtil.isNotBlank(dto.getNote())) {
                        userDeductionCash.setNotes(dto.getNote() + ",满客宝撤销");
                    } else {
                        userDeductionCash.setNotes("满客宝撤销");
                    }
                }
                if (userCation.getChannelType() == 2) {
                    userDeductionCash.setPaymentChannel("2");
                    userTransactionCash.setTransactionType("5");
                    if (StrUtil.isNotBlank(dto.getNote())) {
                        userDeductionCash.setNotes(dto.getNote() + ",京东撤销");
                    } else {
                        userDeductionCash.setNotes("京东撤销");
                    }
                }
                if (userCation.getChannelType() == 3) {
                    userDeductionCash.setPaymentChannel("4");
                    userTransactionCash.setTransactionType("8");
                    if (StrUtil.isNotBlank(dto.getNote())) {
                        userDeductionCash.setNotes(dto.getNote() + ",好店撤销");
                    } else {
                        userDeductionCash.setNotes("好店撤销");
                    }
                }
                userDeductionCash.setTransactionTime(LocalDateTime.now());
                userDeductionCash.setRechargeStream(rechargeStream);
                userDeductionCash.setThirdRechargeStream(StrUtil.isNotBlank(dto.getTransactionSerial()) ? dto.getTransactionSerial() : "");
                userDeductionCash.setDeductionNumber(userOrderInfo.getCashBalance());
                userDeductionCash.setOrderId(userOrderInfo.getOrderId());
                userDeductionCash.setOutOrderNo(userOrderInfo.getOutOrderNo());
                userDeductionMapper.insert(userDeductionCash);
                BeanUtil.copyProperties(userDeductionCash, userTransactionCash);
                userTransactionCash.setTransactionNumber(userOrderInfo.getCashBalance());
                userTransactionCash.setOrderId(userOrderInfo.getOrderId());
                userTransactionCash.setOutOrderNo(userOrderInfo.getOutOrderNo());
                userTransactionCash.setMerchantNumber(headerInfo.getMerchantId());
                userTransactionCash.setThirdRechargeStream(StrUtil.isNotBlank(dto.getTransactionSerial()) ? dto.getTransactionSerial() : "");
                userDeductionCash.setUserType(1);
                userTransactionCash.setUserMealsNumber(sysUser.getUserMealsNumber());
                userTransactionMapper.insert(userTransactionCash);
            }
            // 修改，此行代码之前，sysUser至设置了餐补和现金的修改
            // sysUserMapper.updateById(sysUser);
            sysUserService.lambdaUpdate()
                    .eq(SysUser::getGuid, sysUser.getGuid())
                    .setIncrBy(userOrderInfo.getUserBalance().compareTo(BigDecimal.ZERO) > 0
                            , SysUser::getCardAccount, userOrderInfo.getUserBalance())
                    .setIncrBy(userOrderInfo.getCashBalance().compareTo(BigDecimal.ZERO) > 0
                            , SysUser::getCashAccount, userOrderInfo.getCashBalance())
                    .set(SysUser::getUpdateBy, sysUser.getGuid())
                    .set(SysUser::getUpdateTime, LocalDateTime.now())
                    .update();
            userOrderInfo.setOrderStatus(13);
            userOrderInfo.setRefundAmount(userOrderInfo.getRefundAmount().add(userOrderInfo.getUserBalance()));
            userOrderInfo.setCashRefundAmount(userOrderInfo.getCashRefundAmount().add(userOrderInfo.getCashBalance()));
            userOrderInfo.setAllRefundAmount(userOrderInfo.getRefundAmount().add(userOrderInfo.getCashRefundAmount()));
            userOrderInfo.setCashBalance(BigDecimal.ZERO);
            userOrderInfo.setUserBalance(BigDecimal.ZERO);
            userOrderInfoMapper.updateById(userOrderInfo);
            orderInfoExDto.setRefundAmount(userOrderInfo.getAllRefundAmount());
            try {
                Date now = new Date();
                callbackHelper.callback(CallbackDTO.builder().orderCode(userOrderInfo.getOrderId()).oderMsg(OrderStatus.TRANS_SUCCESS.getDesc()).outTradeNo(dto.getOutTradeNo()).transactionSerial(dto.getTransactionSerial()).tradeSerial(userOrderInfo.getOrderId()).centerTime(LocalDateTime.ofInstant(now.toInstant(), ZoneOffset.ofHours(8))).tradeType("5").build(), headerInfo.getMerchantId());
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        } catch (Exception e) {
            log.error("取消订单失败：", e);
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "取消订单失败", headerInfo.getTraceId());
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        log.info("订单撤销接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(orderInfoExDto), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(orderInfoExDto, headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<UserDeductionVO> qrCodeDeduction(QrCodeDeductionDTO dto, HttpServletRequest request) {

        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        UserDeductionVO userDeductionVO = new UserDeductionVO();

        if (StrUtil.isBlank(dto.getQrCode())) {
            return LaoSheResponse.error(CodeSet.QR_CODE_NULL, headerInfo.getTraceId());
        }

        // 1.校验
        String qrCode = dto.getQrCode();

        if (qrCode.contains("#GDSH#")) {
            String[] code = qrCode.split("#GDSH#");
            if (!code[0].isEmpty()) {
                qrCode = code[0];
            }
        }

        RBucket<String> bucket = redissonClient.getBucket(OPEN_USERID_CODE + qrCode);
        String guid = bucket.get();

        if (StrUtil.isBlank(guid)) {
            return LaoSheResponse.error(CodeSet.QR_CODE_EXPIRED, headerInfo.getTraceId());
        }

        RLock lock = redissonClient.getLock("getAccountLock" + guid);

        try {
            lock.lock(10, TimeUnit.SECONDS);

            UserTransaction userTransactionIsNot = userTransactionMapper.selectOne(Wrappers.<UserTransaction>lambdaQuery().eq(StrUtil.isNotBlank(dto.getTransactionSerial()), UserTransaction::getThirdRechargeStream, dto.getTransactionSerial())
                    .last(" limit 1"));

            if (userTransactionIsNot != null) {
                return LaoSheResponse.error(CodeSet.SERIAL_EXIST, headerInfo.getTraceId());
            }

            log.info("调用支付宝扣费接口 {}", qrCode);
            if (userOrderInfoMapper.selectOne(Wrappers.<UserOrderInfo>lambdaQuery().eq(UserOrderInfo::getOutOrderNo, dto.getOutTradeNo()).last(" limit 1")) != null) {
                return LaoSheResponse.error(CodeSet.ORDER_EXIST_DEBIT_SUCCESS, headerInfo.getTraceId());
            }

            SysUser user = sysUserMapper.selectByGuid(guid);

            //清空缓存
            bucket.delete();

            if (null == user) {
                // 异常 - 清理支付码缓存
                return LaoSheResponse.error(CodeSet.USER_NOT_EXIST.getCode(), CodeSet.USER_NOT_EXIST.getCodeName(), headerInfo.getTraceId());
            }

            if (user.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
                return LaoSheResponse.error(CodeSet.USER_STATUS_EXCEPTION.getCode(), "用户账户已禁用", headerInfo.getTraceId());
            }

            BigDecimal cardNumber = Optional.ofNullable(dto.getBalance()).orElse(BigDecimal.ZERO);
            BigDecimal cashNumber = Optional.ofNullable(dto.getCashBalance()).orElse(BigDecimal.ZERO);

            if (dto.getBalance() != null && dto.getBalance().compareTo(BigDecimal.ZERO) > 0) {
                if (user.getCardState().equals("2")) {
                    return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "账户餐卡账户冻结,无法扣费", headerInfo.getTraceId());
                }
            }
            if (dto.getCashBalance() != null && dto.getCashBalance().compareTo(BigDecimal.ZERO) > 0) {
                if (user.getCashState().equals("2")) {
                    return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "账户现金账户冻结,无法扣费", headerInfo.getTraceId());
                }
            }


            if (dto.getAmount() == null) {
                bucket.delete();
                return LaoSheResponse.error(CodeSet.NOT_AMOUNT_NULL.getCode(), CodeSet.NOT_AMOUNT_NULL.getCodeName(), headerInfo.getTraceId());
            }

            if (dto.getBalance() == null && dto.getCashBalance() == null) {
                return LaoSheResponse.error(CodeSet.NOT_ALL_NULL, headerInfo.getTraceId());
            }

            if (dto.getBalance() != null && dto.getBalance().compareTo(user.getCardAccount()) > 0) {
                return LaoSheResponse.error(CodeSet.INSUFFICIENT_BALANCE, headerInfo.getTraceId());
            }

            if (dto.getCashBalance() != null && dto.getCashBalance().compareTo(user.getCashAccount()) > 0) {
                return LaoSheResponse.error(CodeSet.USER_CASH_ACCOUNT_INSUFFICIENT, headerInfo.getTraceId());
            }
            String note = "";
            UserCation userCation = callbackHelper.getRedisCation(headerInfo.getMerchantId());
            if (userCation.getChannelType() == 1) {
                note = StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() + ",满客宝支付码扣费" : "满客宝支付码扣费";
            } else if (userCation.getChannelType() == 2) {
                note = StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() + ",京东支付码扣费" : "京东支付码扣费";
            } else if (userCation.getChannelType() == 3) {
                note = StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() + ",轨道生活通支付码扣费" : "轨道生活通支付码扣费";
            }

            //生成订单
            UserOrderInfo userOrderInfo = new UserOrderInfo();
            BeanUtil.copyProperties(dto, userOrderInfo);
            userOrderInfo.setOrderId(UserTypeToNameUtil.setRechargeStream());
            userOrderInfo.setOutOrderTime(LocalDateTime.now());
            userOrderInfo.setOrderStatus(8);
            userOrderInfo.setTransactionSerial(dto.getTransactionSerial());
            userOrderInfo.setOutOrderNo(dto.getOutTradeNo());
            userOrderInfo.setStoreId(StrUtil.isNotBlank(dto.getStoreId()) ? dto.getStoreId() : null);
            userOrderInfo.setStoreName(StrUtil.isNotBlank(dto.getStoreName()) ? dto.getStoreName() : null);
            userOrderInfo.setShopName(StrUtil.isNotBlank(dto.getShopName()) ? dto.getShopName() : null);
            userOrderInfo.setMerchantId(StrUtil.isNotBlank(headerInfo.getMerchantId()) ? headerInfo.getMerchantId() : null);
            userOrderInfo.setUserId(user.getUserId());
            userOrderInfo.setGuid(user.getGuid());
            userOrderInfo.setRefundTime(LocalDateTime.now());
            userOrderInfo.setUserMealsNumber(StrUtil.isNotBlank(user.getUserMealsNumber()) ? user.getUserMealsNumber() : "");
            userOrderInfo.setUsername(StrUtil.isNotBlank(user.getUsername()) ? user.getUsername() : "");
            userOrderInfo.setPhone(StrUtil.isNotBlank(user.getPhone()) ? user.getPhone() : "");
            userOrderInfo.setUserJobNumber(StrUtil.isNotBlank(user.getUserJobNumber()) ? user.getUserJobNumber() : "");
            userOrderInfo.setNotes(StrUtil.isNotBlank(dto.getNote()) ? dto.getNote() : "");
            userOrderInfo.setWhetSync("1");
            userOrderInfo.setUserBalance(cardNumber);
            userOrderInfo.setCashBalance(cashNumber);
            userOrderInfo.setAmount(userOrderInfo.getUserBalance().add(userOrderInfo.getCashBalance()));
            userOrderInfo.setUserType(user.getUserType());
            userOrderInfoMapper.insert(userOrderInfo);
            userDeductionVO = getUserDeductionVO(userOrderInfo.getOrderId(), user, dto.getBalance(), dto.getCashBalance(), dto.getOutTradeNo(), dto.getTransactionSerial());
            //TODO 退款交易流水
            String rechargeStreamCard = UserTypeToNameUtil.setRechargeStream();
            insertPay(rechargeStreamCard, userOrderInfo.getOrderId(), userOrderInfo.getOutOrderNo(), note, headerInfo.getMerchantId(), dto.getBalance(), dto.getCashBalance(), user, dto.getTransactionSerial());
            try {
                Date now = new Date();
                callbackHelper.callback(CallbackDTO.builder().orderCode(userOrderInfo.getOrderId()).oderMsg(OrderStatus.TRANS_SUCCESS.getDesc()).outTradeNo(dto.getOutTradeNo()).transactionSerial(dto.getTransactionSerial()).tradeSerial(userOrderInfo.getOrderId()).centerTime(LocalDateTime.ofInstant(now.toInstant(), ZoneOffset.ofHours(8))).tradeType("2").build(), headerInfo.getMerchantId());
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        } catch (Exception e) {
            log.error("二维码扣减失败：", e);
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "二维码扣减失败", headerInfo.getTraceId());
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        log.info("支付码扣费接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(userDeductionVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(userDeductionVO, headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<OrderDetailVO> detail(OrderDetailDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        if (StrUtil.isBlank(dto.getTradeNo()) && StrUtil.isBlank(dto.getOutTradeNo())) {
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "内部订单号和商户订单号不能同时为空", headerInfo.getTraceId());
        }

        LambdaQueryWrapper<UserOrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(dto.getTradeNo())) {
            queryWrapper.eq(UserOrderInfo::getOrderId, dto.getTradeNo());
        } else {
            queryWrapper.eq(UserOrderInfo::getOutOrderNo, dto.getOutTradeNo());
        }
        queryWrapper.last(" limit 1");
        UserOrderInfo userOrderInfo = userOrderInfoMapper.selectOne(queryWrapper);

        if (userOrderInfo == null) {
            return LaoSheResponse.error(CodeSet.ORDER_NOT_EXIST.getCode(), CodeSet.ORDER_NOT_EXIST.getCodeName(), headerInfo.getTraceId());
        }
        OrderDetailVO orderDetailVO = new OrderDetailVO();
        orderDetailVO.setTradeNo(userOrderInfo.getOrderId());
        orderDetailVO.setOutTradeNo(userOrderInfo.getOutOrderNo());
        orderDetailVO.setGuid(StrUtil.isNotBlank(userOrderInfo.getGuid()) ? userOrderInfo.getGuid() : null);
        orderDetailVO.setAmount(userOrderInfo.getAmount());
        //订单时间转时间戳
        orderDetailVO.setTimestamp(UserTypeToNameUtil.getEpochSecond(userOrderInfo.getCreateTime()));
        orderDetailVO.setNote(StrUtil.isNotBlank(userOrderInfo.getNotes()) ? userOrderInfo.getNotes() : null);
        orderDetailVO.setRefundAmount(userOrderInfo.getAllRefundAmount());
        orderDetailVO.setConsumeType(StrUtil.isNotBlank(userOrderInfo.getConsumeType()) ? userOrderInfo.getConsumeType() : null);
        orderDetailVO.setStoreId(StrUtil.isNotBlank(userOrderInfo.getStoreId()) ? userOrderInfo.getStoreId() : null);
        orderDetailVO.setStoreName(StrUtil.isNotBlank(userOrderInfo.getStoreName()) ? userOrderInfo.getStoreName() : null);
        orderDetailVO.setStatus(userOrderInfo.getOrderStatus() != null ? getStatus(userOrderInfo.getOrderStatus()) : null);
        log.info("订单查询接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(orderDetailVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(orderDetailVO, headerInfo.getTraceId());
    }

    private String getStatus(Integer status) {
        String statusName = null;
        //订单状态：0待付款，1已付款，2部分退款 3已退款 4支付失败 5已关闭
        //订单状态(7预受理，8交易成功，9交易失败 10退款成功 11退款失败 12部分退款 13已关闭)
        switch (status) {
            case 7:
                statusName = "0";
                break;
            case 8:
                statusName = "1";
                break;
            case 9, 11:
                statusName = "4";
                break;
            case 10:
                statusName = "3";
                break;
            case 12:
                statusName = "2";
                break;
            case 13:
                statusName = "5";
                break;
        }
        return statusName;
    }

    @Override
    public LaoSheResponse<TransactionDetailVO> transactionFlow(TransactionDetailDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        UserTransaction userTransaction = userTransactionMapper
                .selectOne(Wrappers.<UserTransaction>lambdaQuery()
                        .eq(UserTransaction::getThirdRechargeStream, dto.getTransactionSerial())
                        .eq(UserTransaction::getMerchantNumber, headerInfo.getMerchantId())
                        .in(UserTransaction::getTransactionType, "1", "2", "3")
                        .orderByDesc(UserTransaction::getCreateTime).last(" limit 1"));
        if (userTransaction == null) {
            return LaoSheResponse.error(CodeSet.TRANSACTION_FLOW_NOT_EXIST, headerInfo.getTraceId());
        }

        UserOrderInfo userOrderInfo = userOrderInfoMapper
                .selectOne(Wrappers.<UserOrderInfo>lambdaQuery()
                        .eq(UserOrderInfo::getTransactionSerial, dto.getTransactionSerial())
                        .last(" limit 1"));
        TransactionDetailVO transactionDetailVO = new TransactionDetailVO();
        transactionDetailVO.setTradeNo(userTransaction.getOrderId());
        transactionDetailVO.setOutTradeNo(userTransaction.getOutOrderNo());
        transactionDetailVO.setTransactionSerial(StrUtil.isNotBlank(userTransaction.getThirdRechargeStream()) ? userTransaction.getThirdRechargeStream() : "");
        transactionDetailVO.setGuid(userTransaction.getGuid());
        transactionDetailVO.setAmount(userTransaction.getTransactionNumber());
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        transactionDetailVO.setTimestamp(UserTypeToNameUtil.getEpochSecond(userTransaction.getTransactionTime()));
        transactionDetailVO.setType(userTransaction.getTransactionType().equals("2") || userTransaction.getTransactionType().equals("4") || userTransaction.getTransactionType().equals("10") ? "1" : "3");
        transactionDetailVO.setNote(userTransaction.getNotes());
        transactionDetailVO.setTradeTime(format.format(userTransaction.getTransactionTime()));
        transactionDetailVO.setTradeStatus("1");
        transactionDetailVO.setTradeSerial(userTransaction.getRechargeStream());
        if (userOrderInfo != null && StrUtil.isNotBlank(userOrderInfo.getConsumeType())) {
            transactionDetailVO.setConsumeType(userOrderInfo.getConsumeType());
        }

        log.info("交易流水查询 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(transactionDetailVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(transactionDetailVO, headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<Page<TransactionFlowVO>> transactionFlowHaoDian(TransactionFlowDTO dto, HttpServletRequest request) {

        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        if (dto.getTradeType() != null) {
            if (dto.getTradeType() != 1 && dto.getTradeType() != 2) {
                return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "tradeType无效", headerInfo.getTraceId());
            }
        }

        Page<UserTransaction> page = new Page<>(dto.getPageNum(), dto.getPageSize());

        //交易流水分页查询
        Page<UserTransaction> userTransactionPage = userTransactionMapper.selectPage(page, Wrappers.<UserTransaction>lambdaQuery()
                .eq(UserTransaction::getGuid, dto.getGuid())
                .eq(dto.getTradeType() != null, UserTransaction::getTradeType, dto.getTradeType())
                .orderByDesc(UserTransaction::getCreateTime));

        Page<TransactionFlowVO> transactionFlowVOPage = new Page<>(dto.getPageNum(), dto.getPageSize());
        final List<TransactionFlowVO> transactionFlowVOs = userTransactionPage.getRecords().stream().map(p -> {
            TransactionFlowVO transactionFlowVO = new TransactionFlowVO();
            transactionFlowVO.setAmount(p.getTransactionNumber());
            transactionFlowVO.setTradeDesc(StrUtil.isNotBlank(p.getNotes()) ? p.getNotes() : "");
            transactionFlowVO.setTradeTime(p.getTransactionTime());
            transactionFlowVO.setTradeType(p.getTradeType());
            return transactionFlowVO;
        }).toList();
        transactionFlowVOPage.setRecords(transactionFlowVOs);

        log.info("交易流水查询接口 (好店专用) 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(transactionFlowVOPage), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(transactionFlowVOPage, headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<RechargeFlowDetailVO> rechargeFlowDetail(TransactionDetailDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        UserTransaction userTransaction = userTransactionMapper
                .selectOne(Wrappers.<UserTransaction>lambdaQuery()
                        .eq(UserTransaction::getThirdRechargeStream, dto.getTransactionSerial())
                        .eq(UserTransaction::getMerchantNumber, headerInfo.getMerchantId())
                        .eq(UserTransaction::getTransactionType, "1")
                        .orderByDesc(UserTransaction::getCreateTime).last(" limit 1"));
        if (userTransaction == null) {
            return LaoSheResponse.error(CodeSet.TRANSACTION_FLOW_NOT_EXIST, headerInfo.getTraceId());
        }
        RechargeFlowDetailVO rechargeFlowDetailVO = new RechargeFlowDetailVO();
        rechargeFlowDetailVO.setTransactionSerial(userTransaction.getThirdRechargeStream());
        rechargeFlowDetailVO.setGuid(userTransaction.getGuid());
        rechargeFlowDetailVO.setAmount(userTransaction.getTransactionNumber());
        rechargeFlowDetailVO.setTimestamp(UserTypeToNameUtil.getEpochSecond(userTransaction.getTransactionTime()));
        rechargeFlowDetailVO.setAccountType(userTransaction.getAccountType());
        rechargeFlowDetailVO.setNote(userTransaction.getNotes());
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        rechargeFlowDetailVO.setTradeTime(format.format(userTransaction.getTransactionTime()));
        rechargeFlowDetailVO.setTradeStatus("1");
        rechargeFlowDetailVO.setTradeSerial(userTransaction.getRechargeStream());

        log.info("充值流水查询 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(rechargeFlowDetailVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(rechargeFlowDetailVO, headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<UserBindCardVO> bindCard(UserBindDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        if ("1".equals(dto.getOperationType()) && StrUtil.isEmpty(dto.getUserName())) {
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "用户名称不能为空", headerInfo.getTraceId());
        }
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        //手机号
        if ("1".equals(dto.getSerialType())) {
            queryWrapper.eq(SysUser::getPhone, dto.getSerialValue());
            //工号
        } else if ("2".equals(dto.getSerialType())) {
            queryWrapper.eq(SysUser::getUserJobNumber, dto.getSerialValue());
            //用户ID
        } else if ("3".equals(dto.getSerialType())) {
            queryWrapper.eq(dto.getSerialValue() != null, SysUser::getGuid, dto.getSerialValue());
            //物理卡
        } else if ("4".equals(dto.getSerialType())) {
            queryWrapper.eq(SysUser::getUserMealsNumber, dto.getSerialValue());
        }
        queryWrapper.eq(StrUtil.isNotBlank(dto.getUserName()), SysUser::getUsername, dto.getUserName()).orderByDesc(SysUser::getCreateTime).last(" limit 1");
        SysUser sysUser = sysUserMapper.selectOne(queryWrapper);
        if (sysUser == null) {
            return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
        }

        if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
            return LaoSheResponse.error(CodeSet.USER_STATUS_EXCEPTION.getCode(), "用户账户已禁用", headerInfo.getTraceId());
        }

        UserBindCardVO userBindCardVO = new UserBindCardVO();
        // 用户当前余额，最大两位小数
        userBindCardVO.setBalance(sysUser.getCashAccount().add(sysUser.getCardAccount()));
        if (dto.getOperationType().equals("1")) {
            //绑卡
            sysUser.setIsTheCard(1);
        } else {
            sysUser.setIsTheCard(0);
            sysUser.setUserMealsNumber("");
        }
        sysUser.setPullStatus(1);
        sysUser.setCardAccount(null);//不修改此字段
        sysUser.setCashAccount(null);//不修改此字段
        sysUserMapper.updateById(sysUser);

        userBindCardVO.setGuid(sysUser.getGuid());
        // 用户状态：1-正常，2-禁用，3-注销
        userBindCardVO.setStatus(sysUser.getLockFlag().equals(UserStateEnum.NORMAL.getCode()) ? "1" : "2");
        userBindCardVO.setMobile(sysUser.getPhone());
        userBindCardVO.setName(sysUser.getUsername()); // 用户姓名
        userBindCardVO.setCardId(sysUser.getUserMealsNumber()); // 员工卡物理卡号
        log.info("福利卡解绑 :{}", sysUser);

        log.info("绑卡/解绑接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(userBindCardVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(userBindCardVO, headerInfo.getTraceId());
    }

    @Override
    public LaoSheDateResponse<String> syncCardId(SyncCardIdDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheDateResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        if (StrUtil.isBlank(dto.getUserPhone()) && StrUtil.isBlank(dto.getUserJobNum()) && StrUtil.isBlank(dto.getGuid())) {
            return LaoSheDateResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "手机号和工号和用户id必传其一", headerInfo.getTraceId());
        }
        SysUser sysUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
                .eq(StrUtil.isNotBlank(dto.getUserPhone()), SysUser::getPhone, dto.getUserPhone())
                .eq(StrUtil.isNotBlank(dto.getUserJobNum()), SysUser::getUserJobNumber, dto.getUserJobNum())
                .eq(StrUtil.isNotBlank(dto.getGuid()), SysUser::getGuid, dto.getGuid()).orderByDesc(SysUser::getCreateTime).last(" limit 1"));

        if (sysUser == null) {
            return LaoSheDateResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
        }
        SysUser sysMe = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getUserMealsNumber, dto.getCardId())
                .ne(SysUser::getUserId, sysUser.getUserId())
                .orderByDesc(SysUser::getCreateTime).last(" limit 1"));

        if (sysMe != null) {
            return LaoSheDateResponse.error(CodeSet.CARDID_EXIST, headerInfo.getTraceId());
        }

        if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
            return LaoSheDateResponse.error(CodeSet.USER_STATUS_EXCEPTION.getCode(), "用户账户已禁用", headerInfo.getTraceId());
        }

        if (sysUser.getIsTheCard() == 1 && !dto.getCardId().equals(sysUser.getUserMealsNumber())) {
            return LaoSheDateResponse.error(CodeSet.COMPLETED_BINDCARD, headerInfo.getTraceId());
        }

        sysUser.setUserMealsNumber(dto.getCardId());
        sysUser.setIsTheCard(1);
        sysUser.setPullStatus(1);
        sysUser.setCardAccount(null);//不修改此字段
        sysUser.setCashAccount(null);//不修改此字段
        sysUserMapper.updateById(sysUser);

        log.info("物理卡信息同步接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", "成功", headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheDateResponse.successData("成功", headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<UserGuidVO> addExtraStaff(UserAddExtraStaffDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        UserGuidVO userGuidVO = new UserGuidVO();

        //新增操作
        Integer userType = dto.getUserType();
        if (userType != 2 && userType != 3) {
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "用户类型有误", headerInfo.getTraceId());
        }

        if (dto.getOperationType() != 1 && dto.getOperationType() != 2) {
            return LaoSheResponse.error(CodeSet.INVALID_UPDATE_TYPE.getCode(), CodeSet.INVALID_UPDATE_TYPE.getCodeName(), headerInfo.getTraceId());
        }

        if (dto.getOperationType() == 1) {

            if (StrUtil.isNotBlank(dto.getCardId())) {
                if (!sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserMealsNumber, dto.getCardId())).isEmpty()) {
                    return LaoSheResponse.error(CodeSet.CARDID_EXIST, headerInfo.getTraceId());
                }
            }

            if (sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserJobNumber, dto.getExtattr()).last(" limit 1")) != null) {
                return LaoSheResponse.error(CodeSet.USER_EXIST, headerInfo.getTraceId());
            }
            SysUser user = new SysUser();
            if (StrUtil.isNotBlank(dto.getCardId())) {
                user.setUserMealsNumber(dto.getCardId());
                user.setIsTheCard(1);
            }
            user.setPhone(dto.getUserPhone());
            user.setUsername(dto.getUserName());
            user.setUserJobNumber(dto.getExtattr());
            user.setUserType(dto.getUserType());
            user.setCardState("1");
            user.setCashState("1");
            //TODO 非数字id  暂时不用传
//            user.setDeptId(Long.valueOf(dto.getDeptId()));
            user.setThirdDeptId(dto.getDeptId());
            user.setGuid(IdUtil.nanoId(20));
            UserDepartmentInfo department = userDepartmentInfoMapper
                    .selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery()
                            .eq(UserDepartmentInfo::getDeptId, dto.getDeptId())
                            .last(" limit 1"));
            if (department == null) {
                return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "部门不存在", headerInfo.getTraceId());
            }
            UserDepartmentInfo userDepartmentInfo = userDepartmentInfoMapper
                    .selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery()
                            .eq(UserDepartmentInfo::getDeptId, department.getParentId())
                            .last(" limit 1"));
            if (userDepartmentInfo != null) {
                user.setCompanyId(userDepartmentInfo.getId());
            }
            sysUserMapper.insert(user);
            userGuidVO.setGuid(user.getGuid());
        }
        //修改
        if (dto.getOperationType() == 2) {

            if (StrUtil.isBlank(dto.getGuid())) {
                return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "用户guid不能为空", headerInfo.getTraceId());
            }
            if (StrUtil.isNotBlank(dto.getCardId())) {
                SysUser sysUserTo = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserMealsNumber, dto.getCardId()).orderByDesc(SysUser::getCreateTime).last(" limit 1"));
                if (sysUserTo != null && !sysUserTo.getUserMealsNumber().equals(dto.getCardId())) {
                    return LaoSheResponse.error(CodeSet.CARDID_EXIST, headerInfo.getTraceId());
                }
            }
            // 用户表
            SysUser user = sysUserMapper.selectByGuid(dto.getGuid());

            SysUser userNumber = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserJobNumber, dto.getExtattr()).last(" limit 1"));

            if (userNumber != null && !userNumber.getUserJobNumber().equals(user.getUserJobNumber())) {
                return LaoSheResponse.error(CodeSet.USER_EXIST, headerInfo.getTraceId());
            }

            if (null == user) {
                return LaoSheResponse.error(CodeSet.USER_NOT_EXIST.getCode(), CodeSet.USER_NOT_EXIST.getCodeName(), headerInfo.getTraceId());
            }


            if (user.getIsTheCard() == 1 && StrUtil.isNotBlank(dto.getCardId())) {
                return LaoSheResponse.error(CodeSet.COMPLETED_BINDCARD, headerInfo.getTraceId());
            }
            if (StrUtil.isNotBlank(dto.getCardId())) {
                user.setUserMealsNumber(dto.getCardId());
            }
            user.setPhone(dto.getUserPhone());
            user.setUsername(dto.getUserName());
            user.setUserJobNumber(dto.getExtattr());
            user.setUserType(dto.getUserType());
            UserDepartmentInfo userDepartmentInfo = userDepartmentInfoMapper
                    .selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery()
                            .eq(UserDepartmentInfo::getDeptId, dto.getDeptId())
                            .last(" limit 1"));
            if (userDepartmentInfo == null) {
                return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "部门不存在", headerInfo.getTraceId());
            }
//            user.setDeptId(Long.valueOf(dto.getDeptId()));
            user.setThirdDeptId(dto.getDeptId());
            user.setDeptName(dto.getDeptName());
            user.setGuid(dto.getGuid());
            user.setPullStatus(1);
            sysUserService.updateByGuid(user);
            userGuidVO.setGuid(dto.getGuid());
        }

        log.info("新增编外员工接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(userGuidVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(userGuidVO, headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<UserDeptIdVO> syncExternalDepartment(SyncExtDepartmentDTO dto, HttpServletRequest request) {

        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        UserDeptIdVO userDeptIdVO = new UserDeptIdVO();
        String deptType = dto.getDeptType();

        if (!"2".equals(deptType) && !"3".equals(deptType)) {
            return LaoSheResponse.error(CodeSet.INVALID_UPDATE_TYPE.getCode(), CodeSet.INVALID_UPDATE_TYPE.getCodeName(), headerInfo.getTraceId());
        }

        if (dto.getOperationType() != 1 && dto.getOperationType() != 2) {
            return LaoSheResponse.error(CodeSet.INVALID_UPDATE_TYPE.getCode(), CodeSet.INVALID_UPDATE_TYPE.getCodeName(), headerInfo.getTraceId());
        }

        if (dto.getOperationType() == 1) {

            if (StrUtil.isNotBlank(dto.getParentId())) {
                UserDepartmentInfo selectOne = userDepartmentInfoMapper.selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery()
                        .eq(UserDepartmentInfo::getDeptId, dto.getParentId())
                        .last(" limit 1"));

                if (selectOne == null) {
                    return LaoSheResponse.error(CodeSet.PARENT_DEPT_NULL, headerInfo.getTraceId());
                }
            }

            //新增
            UserDepartmentInfo userDepartmentInfo = new UserDepartmentInfo();
            userDepartmentInfo.setOrgStatus("1");
            userDepartmentInfo.setOrgShortName(dto.getDeptName());
            userDepartmentInfo.setParentId(StrUtil.isNotBlank(dto.getParentId()) ? dto.getParentId() : "131");
            //生成dept_id
            Random random = new Random();
            if (StrUtil.isNotBlank(dto.getDeptId())) {
                if (userDepartmentInfoMapper.selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery()
                        .eq(UserDepartmentInfo::getDeptId, dto.getDeptId()).last(" limit 1")) != null) {
                    return LaoSheResponse.error(CodeSet.DEPT_EXIST, headerInfo.getTraceId());
                }
            }
            userDepartmentInfo.setDeptId(StrUtil.isNotBlank(dto.getDeptId()) ? dto.getDeptId() : String.valueOf(random.nextInt(999999)));
            userDepartmentInfo.setApplyEvent("2");
            userDepartmentInfo.setPullStatus(2);
            userDepartmentInfo.setOrgType("20");
            userDepartmentInfoMapper.insert(userDepartmentInfo);
            userDeptIdVO.setDeptId(userDepartmentInfo.getDeptId());
        }
        if (dto.getOperationType() == 2) {

            if (StrUtil.isNotBlank(dto.getParentId())) {
                UserDepartmentInfo selectOne = userDepartmentInfoMapper.selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery()
                        .eq(UserDepartmentInfo::getDeptId, dto.getParentId()).last(" limit 1"));

                if (selectOne == null) {
                    return LaoSheResponse.error(CodeSet.PARENT_DEPT_NULL, headerInfo.getTraceId());
                }
            }

            //修改
            if (StrUtil.isBlank(dto.getDeptId())) {
                return LaoSheResponse.error(CodeSet.DEPT_NOT_EXIST.getCode(), "部门id不能为空", headerInfo.getTraceId());
            }

            UserDepartmentInfo userDepartmentInfo = userDepartmentInfoMapper.selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery()
                    .eq(UserDepartmentInfo::getDeptId, dto.getDeptId()).last(" limit 1"));

            if (userDepartmentInfo == null) {
                return LaoSheResponse.error(CodeSet.DEPT_NOT_EXIST, headerInfo.getTraceId());
            }

            LaoSheResponse<UserDeptIdVO> PARENT_DEPT_NULL = getUserDeptIdVOLaoSheResponse(dto, headerInfo, userDepartmentInfo);
            if (PARENT_DEPT_NULL != null) return PARENT_DEPT_NULL;
            userDepartmentInfo.setDeptId(dto.getDeptId());
            userDepartmentInfo.setOrgShortName(dto.getDeptName());
            userDepartmentInfo.setPullStatus(2);
            userDepartmentInfoMapper.updateById(userDepartmentInfo);
            userDeptIdVO.setDeptId(dto.getDeptId());
        }

        log.info("新增/修改编外机构信息接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(userDeptIdVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(userDeptIdVO, headerInfo.getTraceId());
    }

    @Override
    public LaoSheDateResponse<String> syncCardIdRecharge(CardIdRechargeDTO dto, HttpServletRequest request) {

        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheDateResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        BigDecimal amount = dto.getRechargeAmount();

        //guid、物理卡号、员工工号、手机号必传其一
        if (StrUtil.isBlank(dto.getCardId()) && StrUtil.isBlank(dto.getUserPhone()) && StrUtil.isBlank(dto.getGuid()) && StrUtil.isBlank(dto.getUserJobNum())) {
            return LaoSheDateResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "guid、物理卡号、员工工号、手机号必传其一", headerInfo.getTraceId());
        }

        if (StrUtil.isBlank(dto.getGuid())) {
            //餐卡充值
            LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(StrUtil.isNotBlank(dto.getGuid()), SysUser::getGuid, dto.getGuid())
                    .eq(StrUtil.isNotBlank(dto.getCardId()), SysUser::getUserMealsNumber, dto.getCardId())
                    .eq(StrUtil.isNotBlank(dto.getUserJobNum()), SysUser::getUserJobNumber, dto.getUserJobNum())
                    .eq(StrUtil.isNotBlank(dto.getUserPhone()), SysUser::getPhone, dto.getUserPhone())
                    .orderByDesc(SysUser::getCreateTime).last(" limit 1");
            SysUser sysUser = sysUserMapper.selectOne(queryWrapper);

            if (sysUser == null) {
                return LaoSheDateResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
            }
            dto.setGuid(sysUser.getGuid());
        }

        RLock lock = redissonClient.getLock("getAccountLock" + dto.getGuid());
        try {
            // 直接获取锁，阻塞式
            lock.lock(10, TimeUnit.SECONDS);

            ResponseDTO recharge = getRecharge(dto.getRechargeSerial(), dto.getRechargeType(), headerInfo, amount);
            if (StrUtil.isNotBlank(recharge.getMsg())) {
                return LaoSheDateResponse.error(recharge.getCode(), recharge.getMsg(), headerInfo.getTraceId());
            }

            UserCation userCation = callbackHelper.getRedisCation(headerInfo.getMerchantId());

            if (userCation.getChannelType() != 1) {
                return LaoSheDateResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "充值暂只支持满客宝", headerInfo.getTraceId());
            }

            SysUser sysUser = sysUserMapper.selectByGuid(dto.getGuid());

            if (sysUser == null) {
                return LaoSheDateResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
            }

            if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
                return LaoSheDateResponse.error(CodeSet.USER_STATUS_EXCEPTION.getCode(), "用户账户已禁用", headerInfo.getTraceId());
            }

            if (sysUser.getCardState().equals("2")) {
                return LaoSheDateResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "该账户餐卡账户已冻结,无法充值", headerInfo.getTraceId());
            }
            String rechargeStream = UserTypeToNameUtil.setRechargeStream();
            //充值流水
            getAccountRecharge(rechargeStream, headerInfo.getMerchantId(), "1", dto.getRechargeSerial(), sysUser, amount, null);
            //生成充值订单
            UserOrderInfo userOrderInfo = new UserOrderInfo();
            BeanUtil.copyProperties(sysUser, userOrderInfo);
            userOrderInfo.setOrderId(UserTypeToNameUtil.setRechargeStream());
            userOrderInfo.setTransactionSerial(dto.getRechargeSerial());
            userOrderInfo.setMerchantId(headerInfo.getMerchantId());
            userOrderInfo.setMerchantName(headerInfo.getMerchantName());
            userOrderInfo.setUserId(sysUser.getUserId());
            userOrderInfo.setGuid(sysUser.getGuid());
            userOrderInfo.setUsername(sysUser.getUsername());
            userOrderInfo.setOutOrderNo(UserTypeToNameUtil.setRechargeStream());
            userOrderInfo.setAmount(dto.getRechargeAmount());
            userOrderInfo.setRefundAmount(dto.getRechargeAmount());
            userOrderInfo.setCashBalance(sysUser.getCashAccount());
            userOrderInfo.setUserBalance(sysUser.getCardAccount());
            userOrderInfo.setOrderStatus(8);
            userOrderInfo.setRefundAmount(dto.getRechargeAmount());
            userOrderInfo.setRefundTime(LocalDateTime.now());
            userOrderInfo.setOutOrderTime(LocalDateTime.now());
            userOrderInfo.setWhetSync("1");
            userOrderInfoMapper.insert(userOrderInfo);
            try {
                Date now = new Date();
                callbackHelper.callback(CallbackDTO.builder().orderCode(userOrderInfo.getOrderId()).oderMsg(OrderStatus.TRANS_SUCCESS.getDesc()).outTradeNo(userOrderInfo.getOutOrderNo()).transactionSerial(dto.getRechargeSerial()).tradeSerial(userOrderInfo.getOrderId()).centerTime(LocalDateTime.ofInstant(now.toInstant(), ZoneOffset.ofHours(8))).tradeType("1").build(), headerInfo.getMerchantId());
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        } catch (Exception e) {
            log.error("福利卡充值失败：", e);
            return LaoSheDateResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "福利卡充值失败", headerInfo.getTraceId());
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        log.info("物理卡/福利账户充值接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", "成功", headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheDateResponse.successData("成功", headerInfo.getTraceId());
    }

    private ResponseDTO getRecharge(String rechargeSerial, String rechargeType, HeaderInfo headerInfo, BigDecimal amount) {
        // 1. 校验
        // 校验充值流水号是否已存在
        UserRechargeRecord rechargeRecord = userRechargeRecordMapper.selectOne(new QueryWrapper<UserRechargeRecord>()
                .lambda()
                .eq(UserRechargeRecord::getThirdRechargeStream, rechargeSerial)
                .orderByDesc(UserRechargeRecord::getCreateTime).last(" limit 1"));

        ResponseDTO responseDTO = new ResponseDTO();

        // 100017-流水号重复，已完成充值
        if (rechargeRecord != null) {
            responseDTO.setCode(CodeSet.TRANSACTION_SERIAL_REPEAT_SUCCESS_RECHARGE.getCode());
            responseDTO.setMsg(CodeSet.TRANSACTION_SERIAL_REPEAT_SUCCESS_RECHARGE.getCodeName());
            return responseDTO;
        }

        // 充值类型(1福利卡 4积分)
        if (StrUtil.isNotBlank(rechargeType)) {
            if (!"1".equals(rechargeType) && !"4".equals(rechargeType)) {
                responseDTO.setCode(CodeSet.SYSTEM_EXCEPTION.getCode());
                responseDTO.setMsg("无效的充值类型");
                return responseDTO;
            }
        }
        //充值金额
        if (0 <= BigDecimal.ZERO.compareTo(amount)) {
            responseDTO.setCode(CodeSet.SYSTEM_EXCEPTION.getCode());
            responseDTO.setMsg("系统异常-充值金额需大于0");
            return responseDTO;
        }
        return responseDTO;
    }

    /**
     * 餐补 现金
     *
     * @param type           餐补传1  现金2
     * @param rechargeSerial
     * @param sysUser
     * @param amount
     */
    private void getAccountRecharge(String rechargeStream, String merchantId, String type, String rechargeSerial, SysUser sysUser, BigDecimal amount, String notes) {
        if (amount.compareTo(BigDecimal.ZERO) != 0) {
            UserCation userCation = callbackHelper.getRedisCation(merchantId);
            if (type.equals("1")) {
                sysUser.setCardAccount(sysUser.getCardAccount().add(amount));
            }
            if (type.equals("2")) {
                sysUser.setCashAccount(sysUser.getCashAccount().add(amount));
            }
            //sysUserMapper.updateById(sysUser);
            sysUserService.lambdaUpdate().eq(SysUser::getUserId, sysUser.getUserId())
                    .setIncrBy(type.equals("1"), SysUser::getCardAccount, amount)
                    .setIncrBy(type.equals("2"), SysUser::getCashAccount, amount)
                    .set(SysUser::getUpdateBy, sysUser.getGuid())
                    .set(SysUser::getUpdateTime, LocalDateTime.now())
                    .update();

            UserRechargeRecord userRechargeRecord = new UserRechargeRecord();
            UserTransaction userTransaction = new UserTransaction();
            BeanUtil.copyProperties(sysUser, userRechargeRecord);
            if (StrUtil.isNotBlank(notes)) {
                userRechargeRecord.setNotes(notes);
            }
            userRechargeRecord.setRechargeNumber(amount);
            if (userCation.getChannelType() == 1) {
                userRechargeRecord.setRechargeChannel("1");
                userTransaction.setTransactionType("1");
            }

            userRechargeRecord.setRechargeType(type);
            userRechargeRecord.setRechargeStream(rechargeStream);
            if (StrUtil.isNotBlank(rechargeSerial)) {
                userRechargeRecord.setThirdRechargeStream(rechargeSerial);
            }
            userRechargeRecordMapper.insert(userRechargeRecord);
            //交易流水
            BeanUtil.copyProperties(sysUser, userTransaction);
            userTransaction.setRechargeStream(rechargeStream);
            if (StrUtil.isNotBlank(rechargeSerial)) {
                userTransaction.setThirdRechargeStream(rechargeSerial);
            }
            if (StrUtil.isNotBlank(notes)) {
                userTransaction.setNotes(notes);
            }
            userTransaction.setTransactionNumber(amount);
            userTransaction.setAccountType(type);
            userTransaction.setTransactionTime(LocalDateTime.now());
            userTransaction.setMerchantNumber(merchantId);
            userTransaction.setTradeType(1);
            userTransaction.setUserMealsNumber(sysUser.getUserMealsNumber());
            userTransactionMapper.insert(userTransaction);
        }
    }

    @Override
    public LaoSheResponse<List<String>> batchRecharge(CardIdBatchRechargeDTO dto, HttpServletRequest request) {
        //批量充值
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        BigDecimal amount = dto.getRechargeAmount();

        ResponseDTO recharge = getRecharge(dto.getRechargeSerial(), dto.getRechargeType(), headerInfo, amount);
        if (StrUtil.isNotBlank(recharge.getMsg())) {
            return LaoSheResponse.error(recharge.getCode(), recharge.getMsg(), headerInfo.getTraceId());
        }

        if (dto.getUserList().isEmpty()) {
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION, headerInfo.getTraceId());
        }

        //充值失败的id
        List<String> idList = new ArrayList<>();

        //guid、物理卡号、员工工号、手机号必传其一
        boolean flag = false;
        for (CardIdBatchRechargeUserVO filter : dto.getUserList()) {
            if (StrUtil.isBlank(filter.getCardId()) && StrUtil.isBlank(filter.getUserPhone()) && StrUtil.isBlank(filter.getGuid()) && StrUtil.isBlank(filter.getUserJobNum())) {
                flag = true;
                break;
            }
        }
        if (flag) {
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "guid、物理卡号、员工工号、手机号必传其一", headerInfo.getTraceId());
        }
        //批量充值
        for (CardIdBatchRechargeUserVO a : dto.getUserList()) {
            LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
            //充值
            if (StrUtil.isBlank(a.getGuid())) {
                idList.add(a.getGuid());
            }
            queryWrapper.eq(StrUtil.isNotBlank(a.getGuid()), SysUser::getGuid, a.getGuid()).eq(StrUtil.isNotBlank(a.getCardId()), SysUser::getUserMealsNumber, a.getCardId()).eq(StrUtil.isNotBlank(a.getUserJobNum()), SysUser::getUserJobNumber, a.getUserJobNum()).eq(StrUtil.isNotBlank(a.getUserPhone()), SysUser::getPhone, a.getUserPhone()).eq(StrUtil.isNotBlank(a.getUserName()), SysUser::getUsername, a.getUserName()).orderByDesc(SysUser::getCreateTime).last(" limit 1");

            SysUser sysUser = sysUserMapper.selectOne(queryWrapper);

            String requestOpen = null;
            if (StrUtil.isNotBlank(a.getGuid())) {
                requestOpen = a.getGuid();
            } else if (StrUtil.isNotBlank(a.getCardId())) {
                requestOpen = a.getCardId();
            } else if (StrUtil.isNotBlank(a.getUserJobNum())) {
                requestOpen = a.getUserJobNum();
            } else if (StrUtil.isNotBlank(a.getUserPhone())) {
                requestOpen = a.getUserPhone();
            }
            if (sysUser == null) {
                idList.add(requestOpen);
            } else if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
                idList.add(requestOpen);
            } else if (sysUser.getCardState().equals("2")) {
                idList.add(requestOpen);
            } else {
                //充值
                String rechargeStream = UserTypeToNameUtil.setRechargeStream();
                getAccountRecharge(rechargeStream, headerInfo.getMerchantId(), "1", dto.getRechargeSerial(), sysUser, amount, null);
            }
        }
        return LaoSheResponse.successData(idList, headerInfo.getTraceId());
    }

    @Override
    public LaoSheTimeResponse<String> syncCashRecharge(CashRechargeDTO dto, HttpServletRequest request) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("现金充值耗时明细-header处理");
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        stopWatch.stop();
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheTimeResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        UserCation userCation = callbackHelper.getRedisCation(headerInfo.getMerchantId());


        if (userCation.getChannelType() != 1) {
            return LaoSheTimeResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "充值暂只支持满客宝", headerInfo.getTraceId());
        }

        BigDecimal amount = dto.getRechargeAmount();

        //guid、物理卡号、员工工号、手机号必传其一
        if (StrUtil.isBlank(dto.getUserPhone()) && StrUtil.isBlank(dto.getGuid()) && StrUtil.isBlank(dto.getUserJobNum())) {
            return LaoSheTimeResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "guid、员工工号、手机号必传其一", headerInfo.getTraceId());
        }
        if (StrUtil.isBlank(dto.getGuid())) {
            stopWatch.start("用户查询");
            //现金充值
            SysUser sysUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
                    .eq(StrUtil.isNotBlank(dto.getGuid()), SysUser::getGuid, dto.getGuid())
                    .eq(StrUtil.isNotBlank(dto.getUserJobNum()), SysUser::getUserJobNumber, dto.getUserJobNum())
                    .eq(StrUtil.isNotBlank(dto.getUserPhone()), SysUser::getPhone, dto.getUserPhone()));
            stopWatch.stop();
            if (sysUser == null) {
                return LaoSheTimeResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
            }
            dto.setGuid(sysUser.getGuid());
        }
        RLock lock = redissonClient.getLock("getAccountLock" + dto.getGuid());

        try {
            // 直接获取锁，阻塞式
            lock.lock(10, TimeUnit.SECONDS);

            stopWatch.start("流水号重复性检查");
            ResponseDTO recharge = getRecharge(dto.getRechargeSerial(), null, headerInfo, amount);
            stopWatch.stop();

            stopWatch.start("开始处理");
            if (StrUtil.isNotBlank(recharge.getMsg())) {
                return LaoSheTimeResponse.error(recharge.getCode(), recharge.getMsg(), headerInfo.getTraceId());
            }

            SysUser sysUser = sysUserMapper.selectByGuid(dto.getGuid());
            if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
                return LaoSheTimeResponse.error(CodeSet.USER_STATUS_EXCEPTION.getCode(), "用户账户已禁用", headerInfo.getTraceId());
            }

            if (sysUser.getCashState().equals("2")) {
                return LaoSheTimeResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "该账户现金账户已冻结,无法充值", headerInfo.getTraceId());
            }

            String rechargeStream = UserTypeToNameUtil.setRechargeStream();
            //充值流水
            getAccountRecharge(rechargeStream, headerInfo.getMerchantId(), "2", dto.getRechargeSerial(), sysUser, amount, null);
            //生成充值订单
            UserOrderInfo userOrderInfo = new UserOrderInfo();
            BeanUtil.copyProperties(sysUser, userOrderInfo);
            userOrderInfo.setOrderId(UserTypeToNameUtil.setRechargeStream());
            userOrderInfo.setTransactionSerial(dto.getRechargeSerial());
            userOrderInfo.setMerchantId(headerInfo.getMerchantId());
            userOrderInfo.setMerchantName(headerInfo.getMerchantName());
            userOrderInfo.setUserId(sysUser.getUserId());
            userOrderInfo.setGuid(sysUser.getGuid());
            userOrderInfo.setUsername(sysUser.getUsername());
            userOrderInfo.setOutOrderNo(UserTypeToNameUtil.setRechargeStream());
            userOrderInfo.setAmount(dto.getRechargeAmount());
            userOrderInfo.setCashRefundAmount(dto.getRechargeAmount());
            userOrderInfo.setCashBalance(sysUser.getCashAccount());
            userOrderInfo.setUserBalance(sysUser.getCardAccount());
            userOrderInfo.setOrderStatus(8);
            userOrderInfo.setRefundTime(LocalDateTime.now());
            userOrderInfo.setOutOrderTime(LocalDateTime.now());
            userOrderInfo.setWhetSync("1");
            userOrderInfoMapper.insert(userOrderInfo);
            try {
                Date now = new Date();
                callbackHelper.callback(CallbackDTO.builder().orderCode(userOrderInfo.getOrderId()).oderMsg(OrderStatus.TRANS_SUCCESS.getDesc()).outTradeNo(userOrderInfo.getOutOrderNo()).transactionSerial(dto.getRechargeSerial()).tradeSerial(userOrderInfo.getOrderId()).centerTime(LocalDateTime.ofInstant(now.toInstant(), ZoneOffset.ofHours(8))).tradeType("1").build(), headerInfo.getMerchantId());
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        } catch (Exception e) {
            log.error("现金充值失败：", e);
            return LaoSheTimeResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "现金充值失败", headerInfo.getTraceId());
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
            if (stopWatch.isRunning()) {
                stopWatch.stop();
            }
        }
        log.info("现金充值各个步骤耗时明细：{}", stopWatch.prettyPrint());

        log.info("现金账户充值接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", "成功", headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheTimeResponse.successData("成功", headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<String> cardIdUnbound(UserCardIdUnboundDTO dto, HttpServletRequest request) {

        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        if (StringUtils.isBlank(dto.getUserPhone()) && StringUtils.isBlank(dto.getGuid())) {
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "guid、手机号不能同时为空", headerInfo.getTraceId());
        }

        SysUser userInfo = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
                .eq(StrUtil.isNotBlank(dto.getGuid()), SysUser::getGuid, dto.getGuid())
                .eq(StrUtil.isNotBlank(dto.getUserPhone()), SysUser::getPhone, dto.getUserPhone()) // 用户手机号
                .eq(SysUser::getUserMealsNumber, dto.getCardId())
                .eq(StrUtil.isNotBlank(dto.getUserName()), SysUser::getUsername, dto.getUserName())
                .orderByDesc(SysUser::getCreateTime).last(" limit 1"));

        if (null == userInfo) {
            return LaoSheResponse.error(CodeSet.USER_NOT_EXIST.getCode(), CodeSet.USER_NOT_EXIST.getCodeName(), headerInfo.getTraceId());
        }

        if (userInfo.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
            return LaoSheResponse.error(CodeSet.USER_STATUS_EXCEPTION, headerInfo.getTraceId());
        }

        //解绑
        // 是否已绑卡
        Integer whetBind = userInfo.getIsTheCard();

        // 非绑定状态不可解绑
        if (whetBind == 0) {
            return LaoSheResponse.error(CodeSet.CANNOT_BE_UNBOUND.getCode(), CodeSet.CANNOT_BE_UNBOUND.getCodeName(), headerInfo.getTraceId());
        }
        //解绑
        userInfo.setIsTheCard(0);
        userInfo.setUserMealsNumber("");
        userInfo.setPullStatus(1);
        userInfo.setCardAccount(null);//不修改此字段
        userInfo.setCashAccount(null);//不修改此字段
        sysUserMapper.updateById(userInfo);
        log.info("福利卡解绑2.25:{}", userInfo);

        log.info("物理卡解绑操作 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", "成功", headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.success("处理成功", headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<ChangeToNormalVO> changeToStaff(ChangeToNormalDTO dto, HttpServletRequest request) {

        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        RLock lockNew = redissonClient.getLock("getAccountLock" + dto.getGuid());

        RLock lockOld = redissonClient.getLock("getAccountLock" + dto.getOriginalGuid());

        ChangeToNormalVO changeToNormalVO = new ChangeToNormalVO();
        try {

            lockNew.lock(10, TimeUnit.SECONDS);
            lockOld.lock(10, TimeUnit.SECONDS);
            //见习员工
            SysUser userOfTrainee = sysUserMapper.selectByGuid(dto.getOriginalGuid());
            if (null == userOfTrainee) {
                return LaoSheResponse.error(CodeSet.JIANXI, headerInfo.getTraceId());
            }
            if (userOfTrainee.getUserType() == 1) {
                return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "该用户是正式员工,不需要转正", headerInfo.getTraceId());
            }

            //正式员工
            SysUser userOfStaff = sysUserMapper.selectByGuid(dto.getGuid());
            if (null == userOfStaff) {
                return LaoSheResponse.error(CodeSet.ZHENGSI, headerInfo.getTraceId());
            }
            if (userOfStaff.getUserType() != 1) {
                return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "该用户不是正式员工", headerInfo.getTraceId());
            }

            //产生流水 退款和充值流水  正式员工   见习员工产生支付流水
            //正式员工产生充值流水
            final String merchantId = headerInfo.getMerchantId();
            final BigDecimal cardAccountOfTrainee = userOfTrainee.getCardAccount();
            getAccountRecharge(UserTypeToNameUtil.setRechargeStream(), merchantId, "1", null, userOfStaff, cardAccountOfTrainee, "见习转正式");
            final BigDecimal cashAccountOfTrainee = userOfTrainee.getCashAccount();
            getAccountRecharge(UserTypeToNameUtil.setRechargeStream(), merchantId, "2", null, userOfStaff, cashAccountOfTrainee, "见习转正式");
            //见习员工产生支付流水
            insertPay(UserTypeToNameUtil.setRechargeStream(), null, null, "见习转正式", merchantId, cardAccountOfTrainee,
                    cashAccountOfTrainee, userOfTrainee, null);

            // 删除旧账户
            SysUser sysUserU1 = new SysUser();
            sysUserU1.setCashState("2");
            sysUserU1.setCardState("2");
            sysUserU1.setLockFlag("9");
            sysUserU1.setPullStatus(1);
            sysUserU1.setUpdateBy(userOfTrainee.getGuid());
            sysUserU1.setUpdateTime(LocalDateTime.now());
            sysUserU1.setUserId(userOfTrainee.getUserId());
            sysUserMapper.updateById(sysUserU1);
            // 更新新账户
            SysUser sysUserU2 = new SysUser();
            sysUserU2.setCashState("1");
            sysUserU2.setCardState("1");
            sysUserU2.setLockFlag("0");
            sysUserU2.setPullStatus(1);
            sysUserU2.setUserId(userOfStaff.getUserId());
            sysUserU1.setUpdateBy(userOfStaff.getGuid());
            sysUserU1.setUpdateTime(LocalDateTime.now());
            sysUserMapper.updateById(sysUserU2);
            changeToNormalVO.setGuid(dto.getGuid());

        } finally {
            if (lockOld.isLocked() && lockOld.isHeldByCurrentThread()) {
                lockOld.unlock();
            }
            if (lockNew.isLocked() && lockNew.isHeldByCurrentThread()) {
                lockNew.unlock();
            }
        }

        log.info("见习转正接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(changeToNormalVO), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(changeToNormalVO, headerInfo.getTraceId());
    }

    @Override
    public LaoSheCallResponse<String> rollBackRecharge(RollBackRechargeDTO dto, HttpServletRequest request) {

        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheCallResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        // 校验充值流水号是否存在
        UserRechargeRecord rechargeRecordGuid = userRechargeRecordMapper.selectOne(new QueryWrapper<UserRechargeRecord>().lambda()
                // 充值流水号
                .eq(UserRechargeRecord::getThirdRechargeStream, dto.getRechargeSerial())
                .eq(UserRechargeRecord::getRechargeType, dto.getChargeType())
                .last(" limit 1"));


        //已撤销
        if (null == rechargeRecordGuid) {
            return LaoSheCallResponse.error(CodeSet.LIUSHUI_IS_NULL, headerInfo.getTraceId());
        }

        if (StrUtil.isBlank(dto.getGuid())) {
            dto.setGuid(rechargeRecordGuid.getGuid());
        }

        RLock lock = redissonClient.getLock("getAccountLock" + dto.getGuid());

        try {
            lock.lock(10, TimeUnit.SECONDS);

            // 校验充值流水号是否存在
            UserRechargeRecord rechargeRecord = userRechargeRecordMapper.selectOne(new QueryWrapper<UserRechargeRecord>().lambda()
                    // 充值流水号
                    .eq(UserRechargeRecord::getThirdRechargeStream, dto.getRechargeSerial())
                    .eq(UserRechargeRecord::getRechargeType, dto.getChargeType())
                    .last(" limit 1"));

            //已撤销
            if (null == rechargeRecord) {
                return LaoSheCallResponse.error(CodeSet.LIUSHUI_IS_NULL, headerInfo.getTraceId());
            }

            if (!rechargeRecord.getRechargeType().equals(dto.getChargeType())) {
                return LaoSheCallResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "该流水号与充值类型不匹配", headerInfo.getTraceId());
            }

            if (rechargeRecord.getRechargeStatus() == 2) {
                return LaoSheCallResponse.error(CodeSet.LIUSHUI_IS_CHEXIAO.getCode(), "该流水已撤销,不可重复操作", headerInfo.getTraceId());
            }

            //撤销充值
            //TODO 生成退款流水
            SysUser sysUser = sysUserMapper.selectById(rechargeRecord.getUserId());

            if (sysUser == null) {
                return LaoSheCallResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
            }

            if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
                return LaoSheCallResponse.error(CodeSet.USER_STATUS_EXCEPTION.getCode(), "用户账户已禁用", headerInfo.getTraceId());
            }

            if (dto.getChargeType().equals("1") && sysUser.getCardState().equals("2")) {
                return LaoSheCallResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "餐卡账户已冻结", headerInfo.getTraceId());
            }

            if (dto.getChargeType().equals("2") && sysUser.getCashState().equals("2")) {
                return LaoSheCallResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "现金账户已冻结", headerInfo.getTraceId());
            }

            String rechargeStreamCard = UserTypeToNameUtil.setRechargeStream();
            String note = "";
            UserCation userCation = callbackHelper.getRedisCation(headerInfo.getMerchantId());
            if (userCation.getChannelType() == 1) {
                note = "满客宝撤销";
            } else if (userCation.getChannelType() == 2) {
                note = "京东撤销";
            } else if (userCation.getChannelType() == 3) {
                note = "轨道生活通撤销";
            }
            if (rechargeRecord.getRechargeNumber().compareTo(BigDecimal.ZERO) > 0) {
                if (rechargeRecord.getRechargeType().equals("1")) {
                    insertPay(rechargeStreamCard, null, null, note, headerInfo.getMerchantId(), rechargeRecord.getRechargeNumber(), BigDecimal.ZERO, sysUser, rechargeRecord.getThirdRechargeStream());
                }
                if (rechargeRecord.getRechargeType().equals("2")) {
                    insertPay(rechargeStreamCard, null, null, note, headerInfo.getMerchantId(), BigDecimal.ZERO, rechargeRecord.getRechargeNumber(), sysUser, rechargeRecord.getThirdRechargeStream());
                }
            }
            //生成充值订单
            UserOrderInfo userOrderInfo = new UserOrderInfo();
            BeanUtil.copyProperties(sysUser, userOrderInfo);
            userOrderInfo.setOrderId(UserTypeToNameUtil.setRechargeStream());
            userOrderInfo.setTransactionSerial(dto.getRechargeSerial());
            userOrderInfo.setMerchantId(headerInfo.getMerchantId());
            userOrderInfo.setMerchantName(headerInfo.getMerchantName());
            userOrderInfo.setUserId(sysUser.getUserId());
            userOrderInfo.setGuid(sysUser.getGuid());
            userOrderInfo.setUsername(sysUser.getUsername());
            userOrderInfo.setOutOrderNo(UserTypeToNameUtil.setRechargeStream());
            userOrderInfo.setAmount(dto.getRechargeAmount());
            if (rechargeRecord.getRechargeType().equals("1")) {
                userOrderInfo.setRefundAmount(dto.getRechargeAmount());
            }
            if (rechargeRecord.getRechargeType().equals("2")) {
                userOrderInfo.setCashRefundAmount(dto.getRechargeAmount());
            }
            userOrderInfo.setCashBalance(sysUser.getCashAccount());
            userOrderInfo.setUserBalance(sysUser.getCardAccount());
            userOrderInfo.setOrderStatus(8);
            userOrderInfo.setRefundAmount(dto.getRechargeAmount());
            userOrderInfo.setRefundTime(LocalDateTime.now());
            userOrderInfo.setOutOrderTime(LocalDateTime.now());
            userOrderInfo.setWhetSync("1");
            userOrderInfoMapper.insert(userOrderInfo);
            try {
                Date now = new Date();
                callbackHelper.callback(CallbackDTO.builder().orderCode(userOrderInfo.getOrderId()).oderMsg(OrderStatus.TRANS_SUCCESS.getDesc()).outTradeNo(userOrderInfo.getOutOrderNo()).transactionSerial(dto.getRechargeSerial()).tradeSerial(userOrderInfo.getOrderId()).centerTime(LocalDateTime.ofInstant(now.toInstant(), ZoneOffset.ofHours(8))).tradeType("5").build(), headerInfo.getMerchantId());
            } catch (Exception e) {
                log.error(e.getMessage());
            }
            //跟改状态
            rechargeRecord.setRechargeStatus(2);
            userRechargeRecordMapper.updateById(rechargeRecord);
        } catch (Exception e) {
            log.error("充值撤销失败：", e);
            return LaoSheCallResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "充值撤销失败", headerInfo.getTraceId());
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        log.info("福利卡/现金账户充值撤销接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", "成功", headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheCallResponse.successRollBackRecharge(headerInfo.getTraceId());
    }

    @Override
    public LaoSheCallResponse<String> withdrawal(WithdrawalDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheCallResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        RLock lock = redissonClient.getLock("getAccountLock" + dto.getGuid());

        try {

            lock.lock(10, TimeUnit.SECONDS);

            UserTransaction userTransactionIsNot = userTransactionMapper.selectOne(Wrappers.<UserTransaction>lambdaQuery().eq(StrUtil.isNotBlank(dto.getWithdrawalSerial()), UserTransaction::getThirdRechargeStream, dto.getWithdrawalSerial())
                    .last(" limit 1"));

            if (userTransactionIsNot != null) {
                return LaoSheCallResponse.error(CodeSet.SERIAL_EXIST, headerInfo.getTraceId());
            }

            //查看流水号是否存在
            if (userTransactionMapper.selectOne(Wrappers.<UserTransaction>lambdaQuery().eq(UserTransaction::getThirdRechargeStream, dto.getWithdrawalSerial()).orderByDesc(UserTransaction::getCreateTime).last(" limit 1")) != null) {
                return LaoSheCallResponse.error(CodeSet.SERIAL_EXIST, headerInfo.getTraceId());
            }

            //提现
            BigDecimal bigDecimal = dto.getWithdrawalAmount().setScale(2, RoundingMode.HALF_UP);

            SysUser sysUser = sysUserMapper.selectByGuid(dto.getGuid());
            if (sysUser == null) {
                return LaoSheCallResponse.error(CodeSet.USER_NOT_EXIST.getCode(), CodeSet.USER_NOT_EXIST.getCodeName(), headerInfo.getTraceId());
            }

            if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
                return LaoSheCallResponse.error(CodeSet.USER_STATUS_EXCEPTION.getCode(), "用户账户已禁用", headerInfo.getTraceId());
            }

            if (dto.getAccountType().equals("1")) {
                if (sysUser.getCardState().equals("2")) {
                    return LaoSheCallResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "餐卡账户已冻结", headerInfo.getTraceId());
                }
                if (bigDecimal.compareTo(sysUser.getCardAccount()) > 0) {
                    return LaoSheCallResponse.error(CodeSet.INSUFFICIENT_BALANCE, headerInfo.getTraceId());
                }
            }

            if (dto.getAccountType().equals("2")) {
                if (sysUser.getCashState().equals("2")) {
                    return LaoSheCallResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "现金账户已冻结", headerInfo.getTraceId());
                }
                if (bigDecimal.compareTo(sysUser.getCashAccount()) > 0) {
                    return LaoSheCallResponse.error(CodeSet.USER_CASH_ACCOUNT_INSUFFICIENT, headerInfo.getTraceId());
                }
            }


            UserOrderInfo userOrderInfo = new UserOrderInfo();
            BeanUtil.copyProperties(sysUser, userOrderInfo);
            userOrderInfo.setOrderId(UserTypeToNameUtil.setRechargeStream());
            String rechargeStream = UserTypeToNameUtil.setRechargeStream();
            String note = "";
            UserCation userCation = callbackHelper.getRedisCation(headerInfo.getMerchantId());
            if (userCation.getChannelType() == 1) {
                note = "满客宝提现";
            } else if (userCation.getChannelType() == 2) {
                note = "京东提现";
            } else if (userCation.getChannelType() == 3) {
                note = "轨道生活通提现";
            }
            if (bigDecimal.compareTo(BigDecimal.ZERO) > 0) {
                if (dto.getAccountType().equals("1")) {
                    insertPay(rechargeStream, userOrderInfo.getOrderId(), null, note, headerInfo.getMerchantId(), bigDecimal, BigDecimal.ZERO, sysUser, dto.getWithdrawalSerial());
                }
                if (dto.getAccountType().equals("2")) {
                    insertPay(rechargeStream, userOrderInfo.getOrderId(), null, note, headerInfo.getMerchantId(), BigDecimal.ZERO, bigDecimal, sysUser, dto.getWithdrawalSerial());
                }
            }
            //生成充值订单
            userOrderInfo.setTransactionSerial(dto.getWithdrawalSerial());
            userOrderInfo.setMerchantId(headerInfo.getMerchantId());
            userOrderInfo.setMerchantName(headerInfo.getMerchantName());
            userOrderInfo.setUserId(sysUser.getUserId());
            userOrderInfo.setGuid(sysUser.getGuid());
            userOrderInfo.setUsername(sysUser.getUsername());
            userOrderInfo.setAmount(dto.getWithdrawalAmount());
            if (dto.getAccountType().equals("1")) {
                userOrderInfo.setRefundAmount(dto.getWithdrawalAmount());
            }
            if (dto.getAccountType().equals("2")) {
                userOrderInfo.setCashRefundAmount(dto.getWithdrawalAmount());
            }
            userOrderInfo.setCashBalance(sysUser.getCashAccount());
            userOrderInfo.setUserBalance(sysUser.getCardAccount());
            userOrderInfo.setOrderStatus(8);
            userOrderInfo.setRefundTime(LocalDateTime.now());
            userOrderInfo.setOutOrderTime(LocalDateTime.now());
            userOrderInfo.setWhetSync("1");
            userOrderInfoMapper.insert(userOrderInfo);
            //需要回调
            try {
                Date now = new Date();
                callbackHelper.callback(CallbackDTO.builder().orderCode(null).oderMsg(OrderStatus.TRANS_SUCCESS.getDesc()).outTradeNo(null).transactionSerial(dto.getWithdrawalSerial()).tradeSerial(userOrderInfo.getOrderId()).centerTime(LocalDateTime.ofInstant(now.toInstant(), ZoneOffset.ofHours(8))).tradeType("4").build(), headerInfo.getMerchantId());
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        log.info("福利卡/现金账户提现接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", "成功", headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheCallResponse.successRollBackRecharge(headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<OrderDeductionVO> register(CallbackUrlDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }
        if (StrUtil.isBlank(dto.getCallbackUrl())) {
            final LaoSheResponse<OrderDeductionVO> error = LaoSheResponse.error();
            error.setErrMsg("无效参数");
            return error;
        }
        //TODO 目前注册回调 没业务口子 直接新增

        UserCation userCation = callbackHelper.getRedisCation(headerInfo.getMerchantId());
        if (userCation == null) {
            return LaoSheResponse.error(CodeSet.MERCHANT_NOT_EXIST, headerInfo.getTraceId());
        }
        userCation.setCallbackUrl(dto.getCallbackUrl());
        userCationMapper.updateById(userCation);
        //覆盖跟新redis索引
        RBucket<UserCation> bucket = redissonClient.getBucket(USER_CATION_KEY + headerInfo.getMerchantId());
        bucket.set(userCation);

        log.info("注册回调接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", "成功", headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.success("成功", headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<List<FinanceVO>> financeList(FinanceDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        //开始时间
        LocalDateTime beginTime = UserTypeToNameUtil.stringToLocalBeginTime(dto.getStartDate());
        //结束时间
        LocalDateTime endTime = UserTypeToNameUtil.stringToLocalEndTime(dto.getEndDate());
        //开始结束时间跨度不能大于31天
        assert endTime != null;
        if (ChronoUnit.DAYS.between(endTime, beginTime) > 31) {
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "开始时间结束时间相差大于31天", headerInfo.getTraceId());
        }

        LambdaQueryWrapper<UserTransaction> queryWrapper = new LambdaQueryWrapper<>();
        if (!dto.getMerchantId().equals("all")) {
            queryWrapper.eq(UserTransaction::getMerchantNumber, dto.getMerchantId());
        }

        queryWrapper.ge(UserTransaction::getTransactionTime, beginTime)
                .le(UserTransaction::getTransactionTime, endTime)
                .orderByAsc(UserTransaction::getCreateTime);

        //TODO 暂时无提现和撤销
        List<UserTransaction> userTransactionList = userTransactionMapper.selectList(queryWrapper);
        userTransactionList = userTransactionList.stream()
                .filter(a -> StrUtil.isNotBlank(a.getTransactionType())).toList();

        if (userTransactionList.isEmpty()) {
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "报表不存在", headerInfo.getTraceId());
        }

        //充值 1
        List<UserTransaction> rechageList = userTransactionList.stream().filter(a -> a.getTransactionType().equals("1")).toList();
        //消费 2
        List<UserTransaction> consumptionList = userTransactionList.stream().filter(a -> a.getTransactionType().equals("2")).toList();
        //提现 3
        List<UserTransaction> withdrawalList = userTransactionList.stream().filter(a -> StrUtil.isNotBlank(a.getNotes())).filter(a -> a.getNotes().contains("提现")).toList();
        //退款 4
        List<UserTransaction> deductionList = userTransactionList.stream().filter(a -> a.getTransactionType().equals("3")).toList();
        //撤销 5
        List<UserTransaction> revokeList = userTransactionList.stream().filter(a -> StrUtil.isNotBlank(a.getNotes())).filter(a -> a.getNotes().contains("撤销")).toList();

        List<FinanceVO> financeVOList = new ArrayList<>();
        Date date = new Date();
        String bucketName = minioUtil.getBucketName();
        //充值
        List<RechargeFinanceExcelVO> rechargeFinanceExcelVOList = new ArrayList<>();
        //消费
        List<ConsumptionFinanceExcelVO> consumptionFinanceExcelVOList = new ArrayList<>();
        //提现
        List<WithdrawalFinanceExcelVO> withdrawalFinanceExcelVOList = new ArrayList<>();
        //退款
        List<DeductionFinanceExcelVO> deductionFinanceExcelVOList = new ArrayList<>();
        //撤销
        List<RevocationFinanceExcelVO> revocationFinanceExcelVOList = new ArrayList<>();

        //充值 1
        rechageList.forEach(b -> {
            RechargeFinanceExcelVO rechargeFinanceExcelVO = new RechargeFinanceExcelVO();
            BeanUtil.copyProperties(b, rechargeFinanceExcelVO);
            rechargeFinanceExcelVO.setAccountType(b.getAccountType().equals("1") ? "福利卡" : "现金");
            rechargeFinanceExcelVO.setTypeName("充值");
            rechargeFinanceExcelVO.setAfterCardNumber(b.getCardAccount());
            rechargeFinanceExcelVO.setAfterCashNumber(b.getCashAccount());
            if (b.getAccountType().equals("1")) {
                rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount().subtract(b.getTransactionNumber()));
                rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount());
            } else {
                rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount());
                rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount().subtract(b.getTransactionNumber()));
            }
            rechargeFinanceExcelVO.setCompanyName("满客宝");
            rechargeFinanceExcelVO.setTime(b.getCreateTime());
            rechargeFinanceExcelVOList.add(rechargeFinanceExcelVO);
        });
        Workbook rechargeBook = ExcelExportUtil.exportExcel(new ExportParams(null, "报表信息"), RechargeFinanceExcelVO.class, rechargeFinanceExcelVOList);
        String rechargePath = minioUtil.uploadFileIntranet(bucketName, UserTypeToNameUtil.getExcelInputSteam(rechargeBook), "scs/download" + date.getTime(), "充值报表信息" + XLSX, false);

        //消费 2
        consumptionList.forEach(b -> {
            ConsumptionFinanceExcelVO rechargeFinanceExcelVO = new ConsumptionFinanceExcelVO();
            BeanUtil.copyProperties(b, rechargeFinanceExcelVO);
            rechargeFinanceExcelVO.setAccountType(b.getAccountType().equals("1") ? "福利卡" : "现金");
            rechargeFinanceExcelVO.setTypeName("消费");
            rechargeFinanceExcelVO.setAfterCardNumber(b.getCardAccount());
            rechargeFinanceExcelVO.setAfterCashNumber(b.getCashAccount());
            if (b.getAccountType().equals("1")) {
                rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount().add(b.getTransactionNumber()));
                rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount());
            } else {
                rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount());
                rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount().add(b.getTransactionNumber()));
            }
            rechargeFinanceExcelVO.setCompanyName("满客宝");
            rechargeFinanceExcelVO.setTime(b.getCreateTime());
            consumptionFinanceExcelVOList.add(rechargeFinanceExcelVO);
        });
        Workbook consumptionBook = ExcelExportUtil.exportExcel(new ExportParams(null, "报表信息"), ConsumptionFinanceExcelVO.class, consumptionFinanceExcelVOList);
        String consumptionPath = minioUtil.uploadFileIntranet(bucketName, UserTypeToNameUtil.getExcelInputSteam(consumptionBook), "scs/download" + date.getTime(), "消费报表信息" + XLSX, false);

        //提现 3
        withdrawalList.forEach(b -> {
            WithdrawalFinanceExcelVO rechargeFinanceExcelVO = new WithdrawalFinanceExcelVO();
            BeanUtil.copyProperties(b, rechargeFinanceExcelVO);
            rechargeFinanceExcelVO.setAccountType(b.getAccountType().equals("1") ? "福利卡" : "现金");
            rechargeFinanceExcelVO.setTypeName("提现");
            rechargeFinanceExcelVO.setAfterCardNumber(b.getCardAccount());
            rechargeFinanceExcelVO.setAfterCashNumber(b.getCashAccount());
            if (b.getAccountType().equals("1")) {
                rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount().add(b.getTransactionNumber()));
                rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount());
            } else {
                rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount());
                rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount().add(b.getTransactionNumber()));
            }
            rechargeFinanceExcelVO.setCompanyName("满客宝");
            rechargeFinanceExcelVO.setTime(b.getCreateTime());
            withdrawalFinanceExcelVOList.add(rechargeFinanceExcelVO);
        });
        Workbook withdrawalBook = ExcelExportUtil.exportExcel(new ExportParams(null, "报表信息"), WithdrawalFinanceExcelVO.class, withdrawalFinanceExcelVOList);
        String withdrawalPath = minioUtil.uploadFileIntranet(bucketName, UserTypeToNameUtil.getExcelInputSteam(withdrawalBook), "scs/download" + date.getTime(), "提现报表信息" + XLSX, false);

        //退款 4
        deductionList.forEach(b -> {
            DeductionFinanceExcelVO rechargeFinanceExcelVO = new DeductionFinanceExcelVO();
            BeanUtil.copyProperties(b, rechargeFinanceExcelVO);
            rechargeFinanceExcelVO.setTypeName("退款");
            rechargeFinanceExcelVO.setAccountType(b.getAccountType().equals("1") ? "福利卡" : "现金");
            rechargeFinanceExcelVO.setAfterCardNumber(b.getCardAccount());
            rechargeFinanceExcelVO.setAfterCashNumber(b.getCashAccount());
            if (b.getAccountType().equals("1")) {
                rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount().add(b.getTransactionNumber()));
                rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount());
            } else {
                rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount());
                rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount().add(b.getTransactionNumber()));
            }
            rechargeFinanceExcelVO.setCompanyName("满客宝");
            rechargeFinanceExcelVO.setTime(b.getCreateTime());
            deductionFinanceExcelVOList.add(rechargeFinanceExcelVO);
        });
        Workbook deductionBook = ExcelExportUtil.exportExcel(new ExportParams(null, "报表信息"), DeductionFinanceExcelVO.class, deductionFinanceExcelVOList);
        String deductionPath = minioUtil.uploadFileIntranet(bucketName, UserTypeToNameUtil.getExcelInputSteam(deductionBook), "scs/download" + date.getTime(), "退款报表信息" + XLSX, false);

        //撤销  5
        revokeList.forEach(b -> {
            RevocationFinanceExcelVO rechargeFinanceExcelVO = new RevocationFinanceExcelVO();
            BeanUtil.copyProperties(b, rechargeFinanceExcelVO);
            rechargeFinanceExcelVO.setTypeName("撤销");
            rechargeFinanceExcelVO.setAccountType(b.getAccountType().equals("1") ? "福利卡" : "现金");
            rechargeFinanceExcelVO.setAfterCardNumber(b.getCardAccount());
            rechargeFinanceExcelVO.setAfterCashNumber(b.getCashAccount());
            if (b.getTransactionType().equals("1")) {
                //充值撤销
                if (b.getAccountType().equals("1")) {
                    rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount().add(b.getTransactionNumber()));
                    rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount());
                } else {
                    rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount());
                    rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount().add(b.getTransactionNumber()));
                }
            } else if (b.getTransactionType().equals("2")) {
                //消费撤销
                if (b.getAccountType().equals("1")) {
                    rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount().subtract(b.getTransactionNumber()));
                    rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount());
                } else {
                    rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount());
                    rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount().subtract(b.getTransactionNumber()));
                }
            } else if (b.getTransactionType().equals("3")) {
                //退款撤销
                if (b.getAccountType().equals("1")) {
                    rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount().subtract(b.getTransactionNumber()));
                    rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount());
                } else {
                    rechargeFinanceExcelVO.setBeforeCardNumber(b.getCardAccount());
                    rechargeFinanceExcelVO.setBeforeCashNumber(b.getCashAccount().subtract(b.getTransactionNumber()));
                }
            }
            rechargeFinanceExcelVO.setCompanyName("满客宝");
            rechargeFinanceExcelVO.setTime(b.getCreateTime());
            revocationFinanceExcelVOList.add(rechargeFinanceExcelVO);
        });
        Workbook revokeBook = ExcelExportUtil.exportExcel(new ExportParams(null, "报表信息"), RevocationFinanceExcelVO.class, revocationFinanceExcelVOList);
        String revokePath = minioUtil.uploadFileIntranet(bucketName, UserTypeToNameUtil.getExcelInputSteam(revokeBook), "scs/download" + date.getTime(), "撤销报表信息" + XLSX, false);

        if (StrUtil.isNotBlank(dto.getTradeType())) {
            FinanceVO financeVO = new FinanceVO();
            //生成excel文档
            financeVO.setDate(dto.getEndDate());
            financeVO.setTradeType(dto.getTradeType());
            if (dto.getTradeType().equals("1")) {
                financeVO.setDownloadUrl(rechargePath);
            } else if (dto.getTradeType().equals("2")) {
                financeVO.setDownloadUrl(consumptionPath);
            } else if (dto.getTradeType().equals("3")) {
                financeVO.setDownloadUrl(withdrawalPath);
            } else if (dto.getTradeType().equals("4")) {
                financeVO.setDownloadUrl(deductionPath);
            } else if (dto.getTradeType().equals("5")) {
                financeVO.setDownloadUrl(revokePath);
            }
            financeVOList.add(financeVO);
        } else {
            //生成全部报表
            //充值
            financeVOList.add(new FinanceVO(dto.getEndDate(), "1", rechargePath));
            financeVOList.add(new FinanceVO(dto.getEndDate(), "2", consumptionPath));
            financeVOList.add(new FinanceVO(dto.getEndDate(), "3", withdrawalPath));
            financeVOList.add(new FinanceVO(dto.getEndDate(), "4", deductionPath));
            financeVOList.add(new FinanceVO(dto.getEndDate(), "5", revokePath));
        }

        log.info("报表生成接口 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(financeVOList), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(financeVOList, headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<String> freezeOperate(UserFreezeDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        if (StrUtil.isBlank(dto.getUserId()) && StrUtil.isBlank(dto.getUserPhone()) && StrUtil.isBlank(dto.getUserJobNum())) {
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "用户id和手机号和工号必须填一个", headerInfo.getTraceId());
        }

        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(dto.getUserId())) {
            queryWrapper.eq(SysUser::getGuid, dto.getUserId());
        } else if (StrUtil.isNotBlank(dto.getUserJobNum())) {
            queryWrapper.eq(SysUser::getUserJobNumber, dto.getUserJobNum());
        } else {
            queryWrapper.eq(SysUser::getPhone, dto.getUserPhone());
        }
        queryWrapper.orderByDesc(SysUser::getCreateTime).last(" limit 1");
        SysUser sysUser = sysUserMapper.selectOne(queryWrapper);
        if (sysUser == null) {
            return LaoSheResponse.error(CodeSet.USER_NOT_EXIST, headerInfo.getTraceId());
        }
        if (dto.getStatus() == 1) {
            sysUser.setLockFlag(UserStateEnum.NORMAL.getCode());
            sysUser.setCardState("1");
            sysUser.setCashState("1");
        } else {
            sysUser.setLockFlag(UserStateEnum.LOCK.getCode());
            sysUser.setCardState("2");
            sysUser.setCashState("2");
        }
        sysUser.setPullStatus(1);
        sysUser.setCardAccount(null);//不修改此字段
        sysUser.setCashAccount(null);//不修改此字段
        sysUserMapper.updateById(sysUser);

        log.info("冻结/解冻 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", "成功", headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData("成功", headerInfo.getTraceId());
    }

    @Override
    public LaoSheResponse<Integer> userCheck(UserCheckDTO dto, HttpServletRequest request) {
        //接口请求开始时间
        long beginCurrentTime = System.currentTimeMillis();
        OpenAPIVerifyDTO openAPIVerifyDTO = headerUtil.openAPIVerify(request);
        HeaderInfo headerInfo = HeaderUtil.getHeaderInfo(request);
        if (StrUtil.isNotBlank(openAPIVerifyDTO.getMsg())) {
            return LaoSheResponse.error(openAPIVerifyDTO.getCode(), openAPIVerifyDTO.getMsg(), headerInfo.getTraceId());
        }

        if (StrUtil.isBlank(dto.getUserId()) && StrUtil.isBlank(dto.getUserPhone()) && StrUtil.isBlank(dto.getUserJobNum())) {
            return LaoSheResponse.error(CodeSet.SYSTEM_EXCEPTION.getCode(), "用户id和手机号和工号必须填一个", headerInfo.getTraceId());
        }

        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(dto.getUserId())) {
            queryWrapper.eq(SysUser::getGuid, dto.getUserId());
        } else if (StrUtil.isNotBlank(dto.getUserJobNum())) {
            queryWrapper.eq(SysUser::getUserJobNumber, dto.getUserJobNum());
        } else {
            queryWrapper.eq(SysUser::getPhone, dto.getUserPhone());
        }
        //TODO 需求不明确
        queryWrapper.orderByDesc(SysUser::getCreateTime).last(" limit 1");
        SysUser sysUser = sysUserMapper.selectOne(queryWrapper);
        int intToOne = 2;
        if (sysUser == null) {
            intToOne = 3;
        } else if (sysUser.getDataSources().equals("1")) {
            intToOne = 1;
        }
        //TODO 见习和内部为员工

        log.info("用户有效性校验 返回值:{}, traceId: {}, 接口响应时间: {}（毫秒）", JSON.toJSONString(intToOne), headerInfo.getTraceId(), System.currentTimeMillis() - beginCurrentTime);
        return LaoSheResponse.successData(intToOne, headerInfo.getTraceId());
    }

    @Override
    public List<UserCompanyVO> getDept(Long id) {
        return sysUserService.getDept(id);
    }

    private @Nullable LaoSheResponse<UserDeptIdVO> getUserDeptIdVOLaoSheResponse(SyncExtDepartmentDTO dto, HeaderInfo headerInfo, UserDepartmentInfo userDepartmentInfo) {
        if (StrUtil.isNotBlank(dto.getParentId())) {
            //非顶级部门
            UserDepartmentInfo parentDept = userDepartmentInfoMapper.selectOne(new QueryWrapper<UserDepartmentInfo>().lambda()
                    // 父部门ID
                    .eq(UserDepartmentInfo::getParentId, dto.getParentId()).last(" limit 1"));

            if (null == parentDept) {
                return LaoSheResponse.error(CodeSet.PARENT_DEPT_NULL.getCode(), CodeSet.PARENT_DEPT_NULL.getCodeName(), headerInfo.getTraceId());
            }
            userDepartmentInfo.setParentId(dto.getParentId());
        } else {
            //顶级部门  父级id设置为1
            userDepartmentInfo.setOrgLevel("2");
            userDepartmentInfo.setParentId("132");
        }
        return null;
    }

    private void insertPay(String rechargeStreamCard, String orderId, String outOrderNo, String note, String merchantId, BigDecimal cardNumber, BigDecimal cashNumber, SysUser user, String transactionSerial) {
        UserCation userCation = callbackHelper.getRedisCation(merchantId);
        cardNumber = Optional.ofNullable(cardNumber).orElse(BigDecimal.ZERO);
        cashNumber = Optional.ofNullable(cashNumber).orElse(BigDecimal.ZERO);
        if (cardNumber.compareTo(BigDecimal.ZERO) != 0) {
            //餐补流水
            //TODO 支付流水
            UserPayment userPaymentCard = new UserPayment();
            UserTransaction userTransactionCard = new UserTransaction();
            BeanUtil.copyProperties(user, userPaymentCard);
            userPaymentCard.setRechargeStream(rechargeStreamCard);
            //TODO 暂定公共接口满客宝
            if (userCation.getChannelType() == 1) {
                userPaymentCard.setPaymentChannel("1");
                userTransactionCard.setTransactionType("2");
            }
            if (userCation.getChannelType() == 2) {
                userPaymentCard.setPaymentChannel("2");
                userTransactionCard.setTransactionType("4");
            }
            if (userCation.getChannelType() == 3) {
                userPaymentCard.setPaymentChannel("4");
                userTransactionCard.setTransactionType("7");
            }

            userPaymentCard.setAccountType("1");
            userPaymentCard.setPayNumber(cardNumber);
            userPaymentCard.setTransactionTime(LocalDateTime.now());
            userPaymentCard.setThirdRechargeStream(transactionSerial);
            userPaymentCard.setAccountType("1");
            userPaymentCard.setNotes(note);
            userPaymentCard.setOrderId(orderId);
            userPaymentCard.setOutOrderNo(StrUtil.isNotBlank(outOrderNo) ? outOrderNo : "");
            userPaymentCard.setCardAccount(user.getCardAccount().subtract(cardNumber));
            userPaymentCard.setCashAccount(user.getCashAccount());
            userPaymentMapper.insert(userPaymentCard);
            BeanUtil.copyProperties(user, userTransactionCard);
            userTransactionCard.setTransactionTime(LocalDateTime.now());
            userTransactionCard.setThirdRechargeStream(transactionSerial);
            userTransactionCard.setTransactionNumber(cardNumber);
            userTransactionCard.setTransactionTime(LocalDateTime.now());
            userTransactionCard.setAccountType("1");
            userTransactionCard.setRechargeStream(rechargeStreamCard);
            userTransactionCard.setMerchantNumber(merchantId);
            userTransactionCard.setNotes(note);
            userTransactionCard.setOrderId(orderId);
            userTransactionCard.setOutOrderNo(StrUtil.isNotBlank(outOrderNo) ? outOrderNo : "");
            userTransactionCard.setCardAccount(user.getCardAccount().subtract(cardNumber));
            userTransactionCard.setCashAccount(user.getCashAccount());
            userTransactionCard.setTradeType(2);
            userTransactionCard.setUserMealsNumber(user.getUserMealsNumber());
            userTransactionMapper.insert(userTransactionCard);
        }
        if (cashNumber.compareTo(BigDecimal.ZERO) != 0) {
            //现金
            //TODO 支付流水
            String rechargePayStream = UserTypeToNameUtil.setRechargeStream();
            UserPayment userPaymentCash = new UserPayment();
            BeanUtil.copyProperties(user, userPaymentCash);
            userPaymentCash.setRechargeStream(rechargePayStream);
            UserTransaction userTransaction = new UserTransaction();
            //TODO 暂定公共接口满客宝
            if (userCation.getChannelType() == 1) {
                userPaymentCash.setPaymentChannel("1");
                userTransaction.setTransactionType("2");
            }
            if (userCation.getChannelType() == 2) {
                userPaymentCash.setPaymentChannel("2");
                userTransaction.setTransactionType("4");
            }
            if (userCation.getChannelType() == 3) {
                userPaymentCash.setPaymentChannel("4");
                userTransaction.setTransactionType("7");
            }
            userPaymentCash.setPayNumber(cashNumber);
            userPaymentCash.setTransactionTime(LocalDateTime.now());
            userPaymentCash.setThirdRechargeStream(transactionSerial);
            userPaymentCash.setAccountType("2");
            userPaymentCash.setNotes(note);
            userPaymentCash.setOrderId(orderId);
            userPaymentCash.setOutOrderNo(StrUtil.isNotBlank(outOrderNo) ? outOrderNo : "");
            userPaymentCash.setCardAccount(user.getCardAccount().subtract(cardNumber));
            userPaymentCash.setCashAccount(user.getCashAccount().subtract(cashNumber));
            userPaymentMapper.insert(userPaymentCash);

            BeanUtil.copyProperties(user, userTransaction);
            userTransaction.setTransactionTime(LocalDateTime.now());
            userTransaction.setThirdRechargeStream(transactionSerial);
            userTransaction.setTransactionNumber(cashNumber);
            userTransaction.setTransactionTime(LocalDateTime.now());
            userTransaction.setAccountType("2");
            userTransaction.setRechargeStream(rechargePayStream);
            userTransaction.setMerchantNumber(merchantId);
            userTransaction.setNotes(note);
            userTransaction.setOrderId(orderId);

            userTransaction.setOutOrderNo(StrUtil.isNotBlank(outOrderNo) ? outOrderNo : "");
            userTransaction.setCardAccount(user.getCardAccount().subtract(cardNumber));
            userTransaction.setCashAccount(user.getCashAccount().subtract(cashNumber));
            userTransaction.setTradeType(2);
            userTransaction.setUserMealsNumber(user.getUserMealsNumber());
            userTransactionMapper.insert(userTransaction);
        }
        sysUserService.lambdaUpdate()
                .eq(SysUser::getUserId, user.getUserId())
                .setDecrBy(cardNumber.compareTo(BigDecimal.ZERO) > 0, SysUser::getCardAccount, cardNumber)
                .setDecrBy(cashNumber.compareTo(BigDecimal.ZERO) > 0, SysUser::getCashAccount, cashNumber)
                .set(SysUser::getUpdateBy, user.getGuid())
                .set(SysUser::getUpdateTime, LocalDateTime.now())
                .update();
    }

    private @NotNull UserDeductionVO getUserDeductionVO(String tradeNo, SysUser user, BigDecimal card, BigDecimal cash, String outTradeNo, String transactionSerial) {
        UserDeductionVO userDeductionVO = new UserDeductionVO();
        userDeductionVO.setTradeNo(tradeNo);
        userDeductionVO.setOutTradeNo(outTradeNo);
        card = Optional.ofNullable(card).orElse(BigDecimal.ZERO);
        cash = Optional.ofNullable(cash).orElse(BigDecimal.ZERO);
        userDeductionVO.setAmount(card.add(cash));
        userDeductionVO.setTransactionSerial(transactionSerial);
        userDeductionVO.setTradeSerial(tradeNo);
        userDeductionVO.setBalance(user.getCardAccount().subtract(card));
        userDeductionVO.setCashBalance(user.getCashAccount().subtract(cash));
        return userDeductionVO;
    }


}
